Je connais la commande grep
et je découvre les fonctionnalités de xargs
. J'ai donc lu la page this qui donne des exemples d'utilisation de la commande xargs
.
Le dernier exemple, exemple 10, me confond. Il est écrit "La commande xargs exécute la commande grep pour rechercher tous les fichiers (parmi les fichiers fournis par la commande find) contenant une chaîne" stdlib.h ""
$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...
Cependant, quelle est la différence en utilisant simplement
$ find . -name '*.c' | grep 'stdlib.h'
?
De toute évidence, je suis toujours aux prises avec ce que fait exactement xargs, alors toute aide est la bienvenue!
$ find . -name '*.c' | grep 'stdlib.h'
Cela conduit la sortie (stdout) * de find
à (stdin of) * grep 'stdlib.h'
sous forme de texte (c’est-à-dire que les noms de fichiers sont traités comme du texte). grep
fait son travail habituel et trouve les lignes correspondantes dans ce texte (tous les noms de fichiers contenant eux-mêmes le motif). Le contenu des fichiers n'est jamais lu.
$ find . -name '*.c' | xargs grep 'stdlib.h'
Ceci construit un commandegrep 'stdlib.h'
auquel chaque résultat de find
est un argument - donc cela cherchera des correspondances à l'intérieur chaque fichier trouvé par find
(xargs
peut être considéré comme étant en train de tourner stdin en arguments des commandes données) *
Utilisez -type f
dans votre commande find ou vous obtiendrez des erreurs de grep
pour les répertoires correspondants. De plus, si les noms de fichiers comportent des espaces, xargs
se trompera mal, utilisez donc le séparateur null en ajoutant -print0
et xargs -0
pour des résultats plus fiables:
find . -type f -name '*.c' -print0 | xargs -0 grep 'stdlib.h'
* ajout de ces points explicatifs supplémentaires comme suggéré dans le commentaire de @cat
xargs prend son entrée standard et le transforme en arguments de ligne de commande.
find . -name '*.c' | xargs grep 'stdlib.h'
est très similaire à
grep 'stdlib.h' $(find . -name '*.c') # UNSAFE, DON'T USE
Et donnera les mêmes résultats tant que la liste des noms de fichiers n'est pas trop longue pour une seule ligne de commande. (Linux prend en charge les mégaoctets de texte sur une seule ligne de commande, vous n'avez donc généralement pas besoin de xargs.)
Mais ces deux sont nuls, parce que ils cassent si vos noms de fichiers contiennent des espaces . find -print0 | xargs -0
fonctionne à la place, mais il en va de même
find . -name '*.c' -exec grep 'stdlib.h' {} +
Cela n'indique jamais les noms de fichiers: find
les regroupe dans une grande ligne de commande et exécute grep
directement.
\;
au lieu de +
exécute grep séparément pour chaque fichier, ce qui est beaucoup plus lent. Ne fais pas ça. +
étant une extension GNU, vous avez donc besoin de xargs
pour le faire efficacement si vous ne pouvez pas supposer que GNU find.
Si vous omettez xargs
, find | grep
fait correspondre ses motifs à la liste des noms de fichiers que find
imprime.
Donc, à ce moment-là, vous pourriez aussi bien faire find -name stdlib.h
. Bien sûr, avec -name '*.c' -name stdlib.h
, vous n'obtiendrez aucune sortie, car ces modèles ne peuvent pas être identiques, et le comportement par défaut de find consiste à utiliser ET les règles ensemble.
Substituez less
à tout moment du processus pour voir la sortie produite par une partie du pipeline.
Pour en savoir plus: http://mywiki.wooledge.org/BashFAQ contient des informations intéressantes.
En règle générale, xargs
est utilisé dans les cas où vous dirigeriez (avec le symbole |
) quelque chose d'une commande à l'autre (Command1 | Command2
), mais la sortie de la première commande n'est pas correctement reçue en tant qu'entrée pour la seconde commande.
Cela se produit généralement lorsque la deuxième commande ne traite pas correctement les données saisies via Standard In (stdin) (par exemple: Plusieurs lignes en entrée, la configuration des lignes, les caractères utilisés en tant que saisie, plusieurs paramètres en entrée, le type de données reçu en tant que entrée, etc.). Pour vous donner un exemple rapide, testez les éléments suivants:
Exemple 1:
ls | echo
- Cela ne fera rien car echo
ne sait pas comment gérer l'entrée qu'il reçoit. Maintenant, dans ce cas, si nous utilisons xargs
name__, l’entrée sera traitée de manière à pouvoir être gérée correctement par echo
(par exemple: comme une seule ligne d’information).
ls | xargs echo
- Ceci affichera toutes les informations de ls
sur une seule ligne
Exemple 2:
Disons que j'ai plusieurs fichiers goLang dans un dossier appelé go. Je les chercherais avec quelque chose comme ça:
find go -name *.go -type f | echo
- Mais si le symbole de canal est présent et que echo
se trouve à la fin, cela ne fonctionnerait pas.
find go -name *.go -type f | xargs echo
- Ici, cela fonctionnerait grâce à xargs
mais si je voulais chaque réponse de la commande find
sur une seule ligne, je procéderais comme suit:
find go -name *.go -type f | xargs -0 echo
- Dans ce cas, le même résultat de find
serait affiché par echo
name__.
Des commandes telles que cp, echo, rm, less
et d'autres nécessitant un meilleur moyen de gérer les entrées ont un avantage lorsqu'elles sont utilisées avec xargs
name__.
xargs
est utilisé pour générer automatiquement des arguments de ligne de commande basés (généralement) sur une liste de fichiers.
Donc, en considérant quelques alternatives à l’utilisation de la commande suivante xargs
:
find . -name '*.c' -print0 | xargs -0 grep 'stdlib.h'
Il y a plusieurs raisons pour l'utiliser à la place d'autres options qui n'étaient pas mentionnées à l'origine dans d'autres réponses:
find . -name '*.c' -exec grep 'stdlib.h' {}\;
générera un processus grep
pour chaque fichier. C'est généralement considéré comme une mauvaise pratique et peut entraîner une lourde charge pour le système si de nombreux fichiers sont trouvés.grep 'stdlib.h' $(find . -name '*.c')
échouera probablement car la sortie de l'opération $(...)
dépassera la longueur maximale de la ligne de commande du shell.Comme indiqué dans d'autres réponses, la raison d'utiliser l'argument -print0
pour find
dans ce scénario et l'argument -0
pour xargs est que les noms de fichiers comportant certains caractères (par exemple, des guillemets, des espaces ou même des nouvelles lignes) sont toujours gérés correctement.