Quelqu'un peut-il suggérer une manière élégante d'accomplir cela?
Contribution:
test instant ()
test instant ()
...
test instant () //total 1000 lines
la sortie doit être:
test instant1 ()
test instant2 ()
test instant1000()
Les lignes vides sont dans mes fichiers d'entrée et il y a beaucoup de fichiers dans le même répertoire que je dois traiter en même temps.
J'ai essayé cela pour remplacer de nombreux fichiers dans le même répertoire et je n'ai pas fonctionné.
for file in ./*; do perl -i -000pe 's/instance$& . ++$n/ge' "$file"; done
les erreurs:
Substitution replacement not terminated at -e line 1.
Substitution replacement not terminated at -e line 1.
et j'ai aussi essayé ça:
perl -i -pe 's/instant/$& . ++$n/ge' *.vs
Cela a fonctionné mais l'index n'a cessé de s'incrémenter d'un fichier à l'autre. Je voudrais réinitialiser cela à 1 lors de la modification d'un nouveau fichier. Des bonnes suggestions?
find . -type f -exec perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} +
fonctionne mais il a remplacé tous les autres fichiers ne devraient pas être remplacés. Je préfère simplement remplacer les fichiers par *.txt
seulement.
test instant ()
?Réponses:
ou avec GNU
awk
:Pour modifier les fichiers sur place, ajoutez l'
-i
option àperl
:Ou récursivement:
Explications
-p
consiste à traiter l'entrée ligne par ligne, à évaluer l'expression transmise à-e
chaque ligne et à l'imprimer. Pour chaque ligne, nous substituons (en utilisant l's/re/repl/flags
opérateur)instant
à lui-même ($&
) et la valeur incrémentée d'une variable++$n
. Leg
drapeau est de faire la substitution globalement (pas seulement une fois), et dee
sorte que le remplacement soit interprété comme du code perl à valuer e̲ (pas une chaîne fixe).Pour l'édition sur place où un appel Perl traite plus d'un fichier, nous voulons
$n
réinitialiser à chaque fichier. Au lieu de cela, nous utilisons$n{$ARGV}
(où$ARGV
est le fichier actuellement traité).Celui
awk
mérite un peu d'explication.Nous utilisons la capacité de GNU
awk
pour séparer les enregistrements sur des chaînes arbitraires (même les regexps). Avec-vRS=instant
, nous réglons le séparateur d'enregistrement surinstant
.RT
est la variable qui contient ce qui a été mis en correspondanceRS
, donc généralement,instant
sauf pour le dernier enregistrement où ce sera la chaîne vide. Dans l'entrée ci-dessus, les enregistrements ($0
) et les terminateurs d'enregistrement (RT
) sont ([$0|RT]
):Il nous suffit donc d'insérer un nombre incrémentiel au début de chaque enregistrement, sauf le premier.
C'est ce que nous faisons ci-dessus. Pour le premier enregistrement,
n
sera vide. Nous définissons ORS (le séparateur d'enregistrement de sortie ) sur RT, de sorte que lesawk
impressionsn $0 RT
. Il le fait sur la seconde expression (++n
) qui est une condition qui est toujours évaluée à vrai (un nombre non nul), et donc l'action par défaut (d'impression$0 ORS
) est effectuée pour chaque enregistrement.la source
sed
n'est vraiment pas le meilleur outil pour le travail, vous voulez quelque chose avec de meilleures capacités de script. Voici quelques choix:perl
Le
-p
moyen "imprime chaque ligne" après avoir appliqué le script fourni-e
. Le-00
mode "paragraphe" est activé pour que les enregistrements (lignes) soient définis par des caractères newline (\n
) consécutifs , ce qui lui permet de traiter correctement les lignes à double interligne.$&
est le dernier motif correspondant et$.
est le numéro de ligne actuel du fichier d'entrée. Lee
ens///e
me permet d'évaluer les expressions de l'opérateur de substitution.awk (cela suppose que vos données sont exactement comme indiqué, avec trois champs séparés par des espaces)
Ici, nous n'incrémentons la
k
variablek
que si la ligne actuelle n'est pas vide,/./
auquel cas nous imprimons également les informations nécessaires. Les lignes vides sont imprimées telles quelles.coquilles diverses
Ici, chaque ligne d'entrée est automatiquement divisée en espaces blancs et les champs sont enregistrés sous
$a
,$b
et$c
. Ensuite, à l'intérieur de la boucle,$c
est augmenté d'un pour chaque ligne pour laquelle$a
est pas vide et sa valeur actuelle est imprimé à côté de la seconde trame,$b
.REMARQUE: toutes les solutions ci-dessus supposent que toutes les lignes du fichier sont du même format. Sinon, la réponse de @ Stéphane est la voie à suivre.
Pour gérer de nombreux fichiers et en supposant que vous souhaitez effectuer cette opération sur tous les fichiers du répertoire en cours, vous pouvez utiliser ceci:
ATTENTION: Cela suppose des noms de fichiers simples sans espaces, si vous avez besoin de traiter quelque chose de plus complexe, optez pour (en supposant
ksh93
,zsh
oubash
):la source
Si vous souhaitez résoudre ce problème avec,
sed
vous pouvez utiliser quelque chose comme ceci (enbash
):ou une solution plus portable serait:
la source