script awk pour remplacer plusieurs occurrences de modèle de chaîne dans la même ligne dans différents fichiers par un numéro correspondant à la chaîne
J'ai besoin d'un script awk qui recherche une chaîne à l'intérieur de <>, s'il en trouve une qu'il n'a pas trouvée avant, il doit le remplacer par la valeur actuelle du compteur d'index (0 au début) et incrémenter le compteur. S'il trouve une chaîne à l'intérieur de <> qu'il connaît déjà, il doit rechercher l'index de la chaîne et le remplacer par l'index. Cela doit être fait sur plusieurs fichiers, ce qui signifie que le compteur ne se réinitialise pas lorsque plusieurs fichiers sont recherchés pour les modèles, uniquement au démarrage du programme Par exemple: file_a.txt:
123abc<abc>xyz
efg
<b>ah
a<c>, <abc>
<c>b
(<abc>, <b>)
file_b.txt:
xyz(<c>, <b>)
xyz<b>xy<abc>z
devrait devenir
file_a_new.txt:
123abc<0>xyz
efg
<1>ah
a<2>, <0>
<2>b
(<0>, <1>)
file_b_new.txt:
xyz(<2>, <1>)
xyz<1>xy<0>z
Ce que j'ai jusqu'à présent:
awk 'match($0, /<[^>]+>/) { k = substr($0, RSTART, RLENGTH)
if (!(k in freq))
freq[k] = n++
$0 = substr($0, 1, RSTART-1) freq[k] substr($0, RSTART+RLENGTH) } { print $0 > (FILENAME ".tmp")
}' files
Mais cela ne peut détecter qu'un seul motif <> par ligne, mais il peut y avoir plusieurs motifs <> par ligne. Alors, comment dois-je changer le code?
Modifier: les fichiers ne doivent pas être édités, mais de nouveaux fichiers doivent être créés
Réponses
Son utilisation gnu-awkest plus facile de cette façon en utilisant RScomme <key>chaîne:
awk -v RS='<[^>]+>' '{ ORS="" } # init ORS to ""
RT { # when RT is set
if (!(RT in freq)) # if RT is not in freq array
freq[RT] = n++ # save n in freq & increment n
ORS="<" freq[RT] ">" # set ORS to < + n + >
}
{
print $0 > ("/tmp/" FILENAME)
}' file_{a,b}.txt
En utilisant n'importe quel awk:
$ cat tst.awk FNR == 1 { close(out) out = FILENAME ".tmp" } { head = "" tail = $0
while ( match(tail,/<[^>]+>/) ) {
tgt = substr(tail,RSTART+1,RLENGTH-2)
if ( !(tgt in map) ) {
map[tgt] = cnt++
}
head = head substr(tail,1,RSTART) map[tgt]
tail = substr(tail,RSTART+RLENGTH-1)
}
print head tail > out
}
$ head file_*.tmp
==> file_a.txt.tmp <==
123abc<0>xyz
efg
<1>ah
a<2>, <0>
<2>b
(<0>, <1>)
==> file_b.txt.tmp <==
xyz(<2>, <1>)
xyz<1>xy<0>z