Voici ma commande (pause intentionnelle):
grep FOO "/Users/gjtorikian/blah" -l | xargs sed -i "" "/FOO/{s/FOO/BAR/g; w /dev/stdout }"
En haut -level: grep
pour FOO dans le répertoire blah
; insérer uniquement le nom de fichier (à cause de -l
) à sed
; sed
effectue un remplacement en ligne (-i ""
) et imprime uniquement le terme modifié en /dev/stdout
.
Si je devais omettre le -l
et pipe, je récupère ceci de grep
:
/Users/gjtorikian/blah/baz.cs:1:FOO /Users/gjtorikian/blah/bar.js:1:FOO
Ce que je veux, cest sed
pour effectuer le remplacement en ligne, puis montrez-moi le fichier et le terme remplacés; par exemple:
/Users/gjtorikian/blah/baz.cs:1:BAR /Users/gjtorikian/blah/bar.js:1:BAR
Une telle chose est-elle possible? Si cela compte, je préférerais le garder uniquement avec grep
/ sed
. Dois-je faire un deuxième grep
après le ?
Commentaires
- Je ne ' trouver un moyen de obtenir le nom du fichier actuel dans sed, donc vous aurez probablement besoin dun second grep.
- De plus, vous navez ' pas besoin du
''
, que ' est la valeur par défaut. - Sous OS X,
''
nest pas la valeur par défaut .
Réponse
Une possibilité serait de transmettre la sortie de grep
à un filtre sed
séparé.
grep -l FOO "/Users/gjtorikian/blah/"* | { tee /dev/fd/3 | xargs sed -i -e "/FOO/{" -e "s/FOO/BAR/g" -e "w /dev/stdout" } 3>&1 | sed "s/:FOO$/:BAR/"
Vous pouvez faire sed
imprimer le numéro de ligne (avec la commande =
) quand il trouve une correspondance et faire plus post-traitement.
Il serait probablement plus clair dutiliser awk.
for x in "/Users/gjtorikian/blah/"*; do awk " sub(/FOO/, "BAR") {found=1; print FILENAME ":" NR ":" "BAR" >"/dev/stderr"} 1 {print} END {exit(!found)} " "$x" >"$x.tmp" && mv "$x.tmp" "$x" done
Réponse
Comme je « mn ot de langue maternelle anglaise, je ne lai probablement pas compris.
Pour « grep » un répertoire, vous avez besoin de « -r ». Lutilisation de « -l » nimprime que le nom du fichier et il arrête la greffe après la première occurrence.
# pattern=/home ; grep -l "$pattern" /etc/[a-z]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home
Réponse
Je pense que vous » rendez le problème trop compliqué en essayant de le faire en une seule fois. Vous pouvez simplement faire un
grep -H -n /Users/gjtorikian/blah | sed "s/\(^.*?:[0-9]+?:\).*FOO.*/\1BAZ/"
pour obtenir la liste des fichiers avec les numéros de ligne et les remplacements (cela devrait fonctionner, tant que vos noms de fichiers ne contiennent pas de deux-points, mais cest quand même une mauvaise idée sous Mac OS …). Ensuite, vous pouvez lancer un
sed -i "" "s/FOO/BAR/g" /Users/gjtorikian/blah
Aucun grep ni xarg nest nécessaire ici (vous pouvez faire un « find … | xarg » si vous avez beaucoup de fichiers). Si vous êtes concerné à propos des duplications, vous pouvez mettre les deux lignes dans un script ou une fonction et y faire des substitutions de variables.
Commentaires
Réponse
Remplacez récursivement FOO par BAR dans le répertoire actuel (mode silencieux)
grep -rl "FOO" | xargs sed -i "s/FOO/BAR/"
Réponse
Une ligne
grep -n FOO * -R|awk -F\: "{ print $1 }"|sort|uniq|while read file; do sed -i "s/FOO/BAR/g" $file; done
sed -i ...
modifie les heures de fichier même si le flux est inchangé.-i
viole la philosophie Unix ( mywiki.wooledge .org / BashFAQ / 021 # Using_nonstandard_tools ). Si vous voulez éviter cela, utilisezex
(par exempleex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah
).