J'ai un file comme celui-ci
... 1562 first part 1563 H col3 H col4 1564 H col3 H col4 ... 3241 H col3 H col4 3242 third part ...
Je veux replace seulement le premier H
de chaque ligne par H#
, avec #
est son nombre d'apparition. La sortie devrait être:
... 1562 first part 1563 H1 col3 H col4 1564 H2 col3 H col4 ... 3241 H1652 col3 H col4 3242 third part ...
Jusqu'à présent, j'ai essayé:
max=`grep -c ' H ' b` while [[ "$i" -le $max ]];do grep -m $i ' H ' b|tail -n1|sed "s/H/H$i/1" let i=i+1 done
Ce code est lent, il doit lire chaque ligne à replace et ne peut pas append la première partie et la troisième partie du file. Y a-t-il une meilleure façon de le faire? Peut-être awk? Je vous remercie.
Vous pouvez par exemple utiliser ceci:
$ awk '/H/{sub("H", "H"++v)}1' file 1562 first part 1563 H1 col3 H col4 1564 H2 col3 H col4 3241 H3 col3 H col4 3242 third part ...
Cela search les lignes contenant H
et remplace H
par H
avec une variable que nous continuons à incrémenter. Notez que vous pourriez utiliser gsub()
au lieu de sub()
si vous vouliez effectuer cette modification dans tous les templates correspondants à la place d'un seul.
Le dernier 1
est une condition vraie, donc il exécute l'action awk par défaut: {print $0}
, c'est-à-dire imprime la ligne complète.
Essaye ça:
awk 'BEGIN { hNum = 1; } { if ($2 == "H") { $2 = "H" hNum; hNum++; } print $0; }' yourFile > outFile
Il exécute awk
utilisant l'espace comme séparateur, donc $2
est le deuxième jeton de chaque ligne et si $2
est égal à "H", remplacez-le par "H" suivi du numéro commençant par 1. Enfin, imprimez la ligne.
Avec perl
:
perl -pe 's/\bH\b\K/++$i/e' file
Vous pouvez replace -pe
par -pi.back -e
pour l'édition sur place avec l'original enregistré en tant que file.back
ou -pi -e
pour aucune sauvegarde.
{ nl -bpH -w1 | sed 's/^\([0-9]*\)[ \t]*\([^H]*.\)/\2\1/' } <<\DATA ... 1562 first part 1563 H col3 H col4 1564 H col3 H col4 ... 3241 H col3 H col4 3242 third part DATA
... 1562 first part 1563 H1 col3 H col4 1564 H2 col3 H col4 ... 3241 H3 col3 H col4 3242 third part
C'est le moyen le plus rapide que je puisse imaginer, surtout avec un très gros file. nl
ne numérotera que les lignes contenant la string H et inserta ce numéro en tête de ligne suivi d'un caractère <tab>
. Il indente toutes les autres lignes avec quelques espaces.
sed
est passé la sortie de nl
sur la |
tuyau. sed
puis remplace la séquence suivante:
\1
) <tab>
ou <space>
caractères \2
) … avec \2\1
.
Donc, les lignes ne contenant pas de H obtiennent ce traitement:
^'' .*.$ = ^.*.''$
Et ceux qui obtiennent celui-ci:
^(digit)*<tab>(not H)*H.*$ = ^(not H)*H(digit)*.*$
… où ''
est une string vide.
Pour une portabilité maximale, remplacez le \t
dans [ \t]
par un caractère littéral <tab>
.