web-dev-qa-db-fra.com

Existe-t-il un équivalent de grep pour les commutateurs find -print0 et xargs -0?

Je veux souvent écrire des commandes comme celle-ci (dans zsh, le cas échéant):

find <somebasedirectory> | \
    grep stringinfilenamesIwant | \
    grep -v stringinfilesnamesIdont | \
    xargs dosomecommand

(ou des combinaisons plus complexes de greps)

Ces dernières années, find a ajouté le commutateur -print0, et xargs a ajouté le -0, qui permet de gérer les fichiers avec des espaces dans le nom de manière élégante en utilisant des noms de fichiers à terminaison nulle, permettant ainsi:

find <somebasedirectory> -print0 | xargs -0 dosomecommand

Cependant, grep (au moins la version que j'ai, GNU grep 2.10 sur Ubuntu), ne semble pas avoir un équivalent à consommer et générer des lignes à terminaison nulle; il a --null, mais cela semble uniquement lié à l'utilisation de -l pour afficher les noms lors de la recherche dans les fichiers directement avec grep.

Existe-t-il une option ou une combinaison d'options équivalente que je peux utiliser avec grep? Sinon, existe-t-il un moyen simple et élégant d’exprimer ma série de commandes en utilisant simplement le -regex de find, ou peut-être Perl?

38
Andrew Ferrier

Utilisez GNU le drapeau --null de Grep

Selon la GNU documentation Grep , vous pouvez utiliser le contrôle du préfixe de ligne en sortie pour gérer les caractères ASCII NUL de la même manière que find et xargs.

-Z
--nul
Générez un octet zéro (caractère ASCII NUL) au lieu du caractère qui suit normalement un nom de fichier. Par exemple, ‘grep -lZ’ génère un octet nul après chaque nom de fichier au lieu de la nouvelle ligne habituelle. Cette option rend la sortie sans ambiguïté, même en présence de noms de fichiers contenant des caractères inhabituels, tels que les nouvelles lignes. Cette option peut être utilisée avec des commandes telles que "find -print0", "Perl -0", "sort -z" et "xargs -0" pour traiter des noms de fichiers arbitraires, même ceux contenant des caractères de nouvelle ligne.

Utilisez tr à partir de GNU Coreutils

Comme l'OP le souligne correctement, cet indicateur est particulièrement utile lors de la gestion des noms de fichiers en entrée ou en sortie. Afin de convertir réellement la sortie de grep afin d'utiliser les caractères NUL comme fins de ligne, vous devez utiliser un outil tel que sed ou tr pour transformer chaque ligne de sortie. Par exemple:

find /etc/passwd -print0 |
    xargs -0 egrep -Z 'root|www' |
    tr "\n" "\0" |
    xargs -0 -n1

Ce pipeline utilisera les NUL pour séparer les noms de fichiers de find, puis convertira les nouvelles lignes en NUL dans les chaînes renvoyées par egrep. Cela transmettra les chaînes terminées par NUL à la prochaine commande du pipeline, qui dans ce cas est simplement xargs, ce qui permet de reconvertir la sortie en chaînes normales, mais il peut s'agir de tout ce que vous voulez.

42
Todd A. Jacobs

Comme vous utilisez déjà GNU find, vous pouvez utiliser ses capacités internes de correspondance des modèles d'expression régulière au lieu de celles-ci grep, par exemple: 

find <somebasedirectory> -regex ".*stringinfilenamesIwant.*" ! -regex ".*stringinfilesnamesIdont.*" -exec dosomecommand {} + 
5
jlliagre

La version la plus récente de la source GNU grep peut désormais utiliser -z/--null pour séparer la sortie par des caractères nuls, alors qu'elle fonctionnait auparavant uniquement avec -l

http://git.savannah.gnu.org/cgit/grep.git/commit/?id=cce2fd5520bba35cf9b264de2f1b6131304f19d2

Cela signifie que votre problème est résolu automatiquement lorsque vous utilisez la version la plus récente.

3
Chiel ten Brinke

Au lieu d'utiliser un tube, vous pouvez utiliser le -exec de find avec le terminateur +. Pour chaîner plusieurs commandes ensemble, vous pouvez générer un shell dans -exec.

find ./ -type f -exec bash -c 'grep "$@" | grep -v something | xargs dosomething' -- {} +
2
jordanm

Utilisation

find <somebasedirectory> -print0 | \
 grep -z stringinfilenamesIwant | \
 grep -zv stringinfilesnamesIdont | \
 xargs -0 dosomecommand

Cependant, le modèle peut ne pas contenir de nouvelle ligne, voir rapport de bogue .

0
jarno