Il me semble que toutes les réponses existantes sur cette page sont fausses, y compris celle qui est marquée comme correcte. Cela vient du fait que la question est formulée de manière ambiguë.
Résumé : Si vous voulez exécuter la commande "exactement une fois pour chaque ligne d'entrée," en passant la ligne entière (sans nouvelle ligne) à la commande comme un un seul argument, alors c'est la meilleure façon de le faire, compatible avec UNIX :
... | tr '\n' '\0' | xargs -0 -n1 ...
Si vous utilisez GNU xargs
et n'ont pas besoin d'être compatibles avec tous les autres UNIX (FreeBSD, Mac OS X, etc.), vous pouvez alors utiliser l'option spécifique à GNU -d
:
... | xargs -d\\n -n1 ...
Maintenant pour la longue explication
Il y a deux problèmes à prendre en compte lors de l'utilisation de xargs :
- comment il divise l'entrée en "arguments" ; et
- le nombre d'arguments à passer à la commande enfant à la fois.
Pour tester le comportement de xargs, nous avons besoin d'un utilitaire qui montre combien de fois il est exécuté et avec combien d'arguments. Je ne sais pas s'il existe un utilitaire standard pour faire cela, mais nous pouvons le coder assez facilement en bash :
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
En supposant que vous l'ayez enregistré sous show
dans votre répertoire courant et le rendre exécutable, voici comment cela fonctionne :
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Maintenant, si la question initiale porte réellement sur le point 2. ci-dessus (comme je le pense, après l'avoir relu plusieurs fois) et qu'elle doit être lue comme suit (les changements sont en gras) :
Comment puis-je faire en sorte que xargs exécute la commande exactement une fois pour chaque argument de l'apport donné ? Son comportement par défaut est de fragmenter le entrée dans les arguments et exécutez la commande le moins de fois possible en passant par plusieurs arguments à chaque instance.
alors la réponse est -n 1
.
Comparons le comportement par défaut de xargs, qui divise l'entrée autour des espaces blancs et appelle la commande aussi peu de fois que possible :
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
et son comportement avec -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Si, d'autre part, la question initiale portait sur le point 1. le fractionnement de l'entrée et qu'elle devait être lue comme ceci (beaucoup de personnes venant ici semblent penser que c'est le cas, ou confondent les deux problèmes) :
Comment puis-je faire en sorte que xargs exécute la commande avec exactement un argument pour chaque ligne d'entrée donnée ? Son comportement par défaut est de fragmenter les lignes autour des espaces blancs .
alors la réponse est plus subtile.
On pourrait penser que -L 1
pourrait être utile, mais il s'avère qu'elle ne change pas l'analyse des arguments. Elle n'exécute la commande qu'une fois pour chaque ligne d'entrée, avec autant d'arguments qu'il y en avait sur cette ligne d'entrée :
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
De plus, si une ligne se termine par un espace, elle est ajoutée à la suivante :
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Clairement, -L
ne consiste pas à changer la façon dont xargs divise l'entrée en arguments.
Le seul argument qui le fait de manière multiplateforme (à l'exception des extensions GNU) est le suivant -0
qui divise l'entrée autour des octets NUL.
Ensuite, il suffit de traduire les nouvelles lignes en NUL à l'aide de la fonction tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Maintenant, l'analyse des arguments semble correcte, y compris l'espacement de fin de ligne.
Enfin, si vous combinez cette technique avec -n 1
vous obtenez exactement une exécution de commande par ligne d'entrée, quelle que soit l'entrée que vous avez, ce qui peut être encore une autre façon de voir la question originale (peut-être la plus intuitive, étant donné le titre) :
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
Comme mentionné ci-dessus, si vous utilisez GNU xargs
vous pouvez remplacer le tr
avec l'option spécifique à GNU -d
:
$ echo $'one \ntwo\nthree and four' | xargs -d\\n -n1 ./show
-> "one "
-> "two"
-> "three and four"
5 votes
Dans l'exemple que vous donnez,
find /path -type f -delete
serait encore plus efficace :)0 votes
Essayez de ne pas utiliser xargs...
7 votes
OP, je sais que cette question est très ancienne, mais elle apparaît toujours sur Google et, à mon avis, la réponse acceptée est fausse. Voir ma réponse plus longue ci-dessous.
1 votes
Veuillez envisager de changer votre acceptation pour la réponse de @Tobia qui est bien meilleure. La réponse acceptée ne gère pas les espaces dans les noms et n'autorise pas les arguments multiples à la commande xargs, ce qui est l'une des principales caractéristiques de xargs.