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

  • sed -i ... modifie les heures de fichier même si le flux est inchangé.
  • @jww: vous ' avez raison, que ' car est un éditeur de flux et non un éditeur de fichiers, donc loption -i viole la philosophie Unix ( mywiki.wooledge .org / BashFAQ / 021 # Using_nonstandard_tools ). Si vous voulez éviter cela, utilisez ex (par exemple ex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah).

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 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *