web-dev-qa-db-fra.com

Utiliser grep et sed pour rechercher et remplacer une chaîne

J'utilise ce qui suit pour rechercher récursivement un répertoire dans une chaîne et le remplacer par un autre:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g'

Cela fonctionne bien. Le seul problème est que si la chaîne n'existe pas, alors sed échoue car il ne reçoit aucun argument. C'est un problème pour moi puisque j'exécute ceci automatiquement avec ANT et que la construction échoue puisque sed échoue.

Y a-t-il un moyen de le rendre infaillible au cas où la chaîne ne serait pas trouvée?

Je suis intéressé par une solution simple à une ligne que je peux utiliser (pas nécessairement avec grep ou sed mais avec des commandes unix communes comme celles-ci).

67
Michael

Vous pouvez utiliser find et -exec directement dans sed plutôt que de localiser d'abord oldstr avec grep. C'est peut-être un peu moins efficace, mais ce n'est peut-être pas important. De cette façon, le remplacement sed est exécuté sur tous les fichiers répertoriés par find, mais si oldstr ne figure pas dans ce répertoire, il ne fonctionnera évidemment pas.

find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
70

Votre solution est ok. essayez seulement de cette façon:

files=$(grep -rl oldstr path) && echo $files | xargs sed....

alors exécutez le xargs uniquement lorsque grep renvoie 0, par exemple. quand trouvé la chaîne dans certains fichiers.

9
jm666

J'ai pris l'idée de Vlad et l'ai modifiée un peu. Au lieu de

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

Quels rendements

sed: couldn't edit /dev/null: not a regular file

Je fais dans 3 connexions différentes au serveur distant

touch deleteme
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' ./deleteme
rm deleteme

Bien que cela soit moins élégant et nécessite 2 connexions supplémentaires sur le serveur (il y a peut-être un moyen de tout faire en une seule ligne), il fait aussi le travail efficacement

7
Michael

La norme xargs ne dispose d'aucun moyen efficace. vous feriez mieux d'utiliser find -exec comme quelqu'un l’a suggéré, ou enveloppez le sed dans un script qui ne fait rien s’il n’ya pas d’argument. GNU xargs a le --no-run-if-empty Option et BSD/OS X xargs a le -L option qui semble devoir faire quelque chose de similaire.

7
geekosaur

Je pense que sans utiliser -exec vous pouvez simplement fournir /dev/null comme au moins un argument au cas où rien ne serait trouvé:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
4
user405725

Mon cas d'utilisation était que je voulais remplacer foo:/Drive_Letter avec foo:/bar/baz/xyz Dans mon cas, j'ai pu le faire avec le code suivant. J'étais dans le même répertoire que celui où se trouvaient la plupart des fichiers.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

espérons que cela a aidé.

1
neo7