Je connais la grep
commande et j'apprends les fonctionnalités de xargs
, alors j'ai lu cette page qui donne quelques exemples sur la façon d'utiliser la xargs
commande.
Je suis confus par le dernier exemple, l'exemple 10. Il dit "La commande xargs exécute la commande grep pour trouver tous les fichiers (parmi les fichiers fournis par la commande find) qui contenaient 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 différence y a-t-il à utiliser simplement
$ find . -name '*.c' | grep 'stdlib.h'
?
Évidemment, je lutte toujours avec ce que fait exactement xargs, donc toute aide est appréciée!
command-line
grep
xargs
AlphaOmega
la source
la source
Réponses:
Cela dirige la sortie (stdout) * de
find
(stdin de) *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 qui contiennent eux-mêmes le modèle). Le contenu des fichiers n'est jamais lu.Ceci construit une commande
grep 'stdlib.h'
dont chaque résultatfind
est un argument - donc cela cherchera des correspondances à l' intérieur de chaque fichier trouvé parfind
(xargs
peut être considéré comme transformant son stdin en arguments aux commandes données) *Utilisez-le
-type f
dans votre commande find, sinon vous obtiendrez des erreursgrep
pour les répertoires correspondants. De plus, si les noms de fichiers ont des espaces, ilsxargs
vont mal se visser, alors utilisez le séparateur nul en ajoutant-print0
etxargs -0
pour des résultats plus fiables:* ajouté ces points explicatifs supplémentaires comme suggéré dans le commentaire de @cat
la source
|
redirige stdout vers stdin de grep qui n'est pas le même que les arguments de grep et donne des résultats confus.find -name '*.c' -exec grep stdlib.h {} +
. Je n'utilise pratiquement pas de xargs. Aussi surpris que personne n'ait mentionné que xargs sert un objectif similaire à lagrep $(find)
substitution de commandes, j'ai donc écrit ma propre réponse. Expliquer xargs comme substitution de commande avec moins de limitations et de problèmes semble naturel.find -delete
pour ce cas particulier? Ou pour les commandes autres querm
, si vous avez GNU find, puis les-exec some_command {} +
groupes en lots comme xargs, au lieu du\;
comportement d'exécution de la commande séparément pour chacun.find
exécute la commande sur chaque fichier si et seulement s'il utilise-exec command \;
Bothxargs
et-exec command \+
appellera la commande avec le nombre maximum d'arguments autorisés par le système. En d'autres termes, ils sont équivalentsxargs prend son entrée standard et la transforme en arguments de ligne de commande.
find . -name '*.c' | xargs grep 'stdlib.h'
est très similaire à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 des mégaoctets de texte sur une seule ligne de commande, donc vous n'avez généralement pas besoin de xargs.)
Mais ces deux choses sont nulles, car elles se cassent si vos noms de fichiers contiennent des espaces . Au lieu de cela,
find -print0 | xargs -0
fonctionne, mais il en va de mêmeCela ne
find
dirige jamais les noms de fichiers n'importe où: les regroupe dans une grande ligne de commande et s'exécutegrep
directement.\;
au lieu d'+
exécuter grep séparément pour chaque fichier, ce qui est beaucoup plus lent. Ne fais pas ça. Mais+
c'est une extension GNU, vous devezxargs
donc le faire efficacement si vous ne pouvez pas supposer que GNU trouve.Si vous omettez
xargs
,find | grep
son modèle correspond-il à la liste des noms de fichiersfind
s'imprime.Donc, à ce stade, vous pourriez tout 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 correspondre, et le comportement par défaut de find est de ET les règles ensemble.Remplacer
less
à tout moment du processus pour voir quelle sortie n'importe quelle partie du pipeline produit.Pour en savoir plus: http://mywiki.wooledge.org/BashFAQ a quelques bonnes choses.
la source
-d
définir le séparateur, de sorte que vous pouvez utiliser-d'\n'
pour gérer une liste séparée par des retours à la ligne, ce qui peut être utile si vous gérez une liste de noms de fichiers dans un fichier, etc. (tant que les noms de fichiers n'ont pas de nouvelles lignes en eux, c'est.)myfunc(){ local IFS=$'\n'; fgrep
stdlib.h` $ (find); }
fonctionne également avec le même effet. Ou en tant que ligne unique, un(IFS=...; cmd...)
sous - shell fonctionne également pour contenir le changement d'IFS sans avoir à l'enregistrer / le restaurer.command $( find )
type de choses. Les noms de fichiers problématiques avec des espaces et des caractères spéciaux peuvent briser ce type de chose. Au moins, citez deux fois la substitution de commande.IFS
ce qui équivaut à utiliserxargs '-d\n'
. L'expansion des globes et le traitement des métacaractères du shell se produisent avant les effets de la substitution de commandes, donc je pense que c'est sûr même avec les noms de fichiers qui contiennent$()
ou>
. A convenu que l'utilisation de la séparation des mots sur la substitution de commandes n'est pas une bonne pratique, sauf pour une utilisation interactive unique où vous savez quelque chose sur les noms de fichiers. Maiscommand "$(find)"
n'est utile que si vous vous attendez à ce qu'il produise exactement 1 nom de fichier ...En général,
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 comme entrée pour la deuxième commande.Cela se produit généralement lorsque la deuxième commande ne gère pas correctement l'entrée de données via Standard In (stdin) (par exemple: plusieurs lignes en entrée, la façon dont les lignes sont configurées, les caractères utilisés en entrée, 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 carecho
ne sait pas gérer l'entrée qu'il reçoit. Maintenant, dans ce cas, si nous l'utilisons,xargs
il traitera l'entrée d'une manière qui peut être gérée correctement parecho
( par exemple: comme une seule ligne d'information)ls | xargs echo
- Cela affichera toutes les informationsls
sur une seule ligneExemple 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 du tuyau là-bas etecho
à la fin, ça ne marcherait pas.find go -name *.go -type f | xargs echo
- Ici, cela fonctionnerait grâce àxargs
mais si je voulais chaque réponse de lafind
commande sur une seule ligne, je ferais ce qui suit:find go -name *.go -type f | xargs -0 echo
- Dans ce cas, la même sortie defind
serait indiquée parecho
.Les commandes comme
cp, echo, rm, less
et celles qui ont besoin d'une meilleure façon de gérer l'entrée obtiennent un avantage lorsqu'elles sont utilisées avecxargs
.la source
xargs
est utilisé pour générer automatiquement des arguments de ligne de commande basés (généralement) sur une liste de fichiers.Considérant donc quelques alternatives à l'utilisation de la
xargs
commande followoing :Il y a plusieurs raisons de l'utiliser au lieu 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 ungrep
processus pour chaque fichier - ceci est généralement considéré comme une mauvaise pratique et peut mettre une grosse charge sur le système s'il y a plusieurs fichiers trouvés.grep 'stdlib.h' $(find . -name '*.c')
commande échouera probablement, car la sortie de l'$(...)
opération dépassera la longueur de ligne de commande maximale du shellComme mentionné dans d'autres réponses, la raison d'utiliser l'
-print0
argument tofind
dans ce scénario et l'-0
argument xargs est que les noms de fichiers avec certains caractères (par exemple les guillemets, les espaces ou même les nouvelles lignes) sont toujours traités correctement.la source