Comment puis-je faire en sorte que xargs exécute la commande exactement une fois pour chaque ligne d'entrée donnée? Son comportement par défaut consiste à couper les lignes et à exécuter la commande une fois, en passant plusieurs lignes à chaque instance.
Sur http://en.wikipedia.org/wiki/Xargs :
find / path -type f -print0 | xargs -0 rm
Dans cet exemple, find alimente l'entrée de xargs avec une longue liste de noms de fichiers. xargs divise ensuite cette liste en sous-listes et appelle rm une fois pour chaque sous-liste. C'est plus efficace que cette version fonctionnellement équivalente:
find / path -type f -exec rm '{}' \;
Je sais que find a le drapeau "exec". Je cite juste un exemple illustratif d'une autre ressource.
find /path -type f -delete
serait encore plus efficace :)Réponses:
Les éléments suivants ne fonctionneront que si vous n'avez pas d'espace dans votre entrée:
à partir de la page de manuel:
la source
xargs -n 1
celui que vous avez donné montrait une "liste d'arguments trop longue".MAX-LINES
est omis, il vaut 1 par défaut, donc celaxargs -l
suffit. Tu voisinfo xargs
.echo "foo bar" | xargs -n1 echo
. par conséquent, si vous canalisez des éléments comme «ls», il ne gérera pas bien les espaces.-L 1
ne répond pas à la question d'origine, et-n 1
ne le fait que dans l'une des interprétations possibles. Voir ma longue réponse ci-dessous.-L 1
fait. Pour moi, l'OP semblait clairement essayer d'éviter le comportement de segmentation par défaut, et puisque cela a été accepté, je suppose que j'avais raison. Votre réponse concerne un cas d'utilisation légèrement différent où vous souhaitez également le comportement de segmentation.Il me semble que toutes les réponses existantes sur cette page sont fausses, y compris celle marquée comme correcte. Cela découle 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 donnée", en passant la ligne entière (sans la nouvelle ligne) à la commande comme un seul argument, alors c'est la meilleure façon compatible UNIX de le faire:
GNU
xargs
peut ou non avoir des extensions utiles qui vous permettent de vous en débarrassertr
, mais elles ne sont pas disponibles sur OS X et d'autres systèmes UNIX.Maintenant pour la longue explication…
Il y a deux problèmes à prendre en compte lors de l'utilisation de xargs:
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 le faire, mais nous pouvons le coder assez facilement en bash:
En supposant que vous l'enregistrez comme
show
dans votre répertoire actuel et que vous le rendiez exécutable, voici comment cela fonctionne:Maintenant, si la question d'origine concerne vraiment le point 2 ci-dessus (comme je pense que c'est le cas, après l'avoir lu plusieurs fois) et qu'elle doit être lue comme ceci (changements en gras):
alors la réponse est
-n 1
.Comparons le comportement par défaut de xargs, qui divise l'entrée autour des espaces et appelle la commande aussi peu de fois que possible:
et son comportement avec
-n 1
:Si, d'un autre côté, la question initiale portait sur le point 1, le fractionnement des entrées et qu'il devait être lu comme ceci (beaucoup de gens qui viennent ici semblent penser que c'est le cas, ou confondent les deux problèmes):
alors la réponse est plus subtile.
On pourrait penser que cela
-L 1
pourrait être utile, mais il s'avère que cela ne change pas l'analyse des arguments. Il n'exécute la commande qu'une seule fois pour chaque ligne d'entrée, avec autant d'arguments qu'il y en avait sur cette ligne d'entrée:Non seulement cela, mais si une ligne se termine par un espace, elle est ajoutée à la suivante:
De toute évidence, il
-L
ne s'agit pas de changer la façon dont xargs divise l'entrée en arguments.Le seul argument qui le fait de manière multiplateforme (à l'exclusion des extensions GNU) est
-0
, qui divise l'entrée en octets NUL.Ensuite, il suffit de traduire les nouvelles lignes en NUL à l'aide de
tr
:Maintenant, l'analyse des arguments semble correcte, y compris les espaces de fin.
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 une autre façon de regarder la question d'origine (peut-être la plus intuitive, compte tenu du titre):la source
-L
exécute la commande une fois par ligne d'entrée (mais un espace à la fin d'une ligne la joint à la ligne suivante, et la ligne est toujours divisée en arguments selon les espaces); tandis que-n
exécute la commande une fois par argument d'entrée. Si vous comptez le nombre de->
dans les exemples de sortie, il s'agit du nombre d'./show
exécutions du script .xargs
peut ou non avoir des extensions utiles qui vous permettent de vous en débarrasser.tr
Il a une telle extension très utile; fromxargs --help
- -d, --delimiter = CHARACTER les éléments du flux d'entrée sont séparés par CHARACTER, et non par des espaces; désactive le traitement des devis et des contre-obliques et le traitement EOF logique-L
.-L
ne dit pas combien de fois exécuter le script par ligne, il dit combien de lignes de données d'entrée à consommer à la fois.Si vous souhaitez exécuter la commande pour chaque ligne (c'est-à-dire le résultat) en provenance de
find
, alors de quoi avez-vous besoinxargs
?Essayer:
find
chemin de-type f -exec
votre commande-{} \;
où le littéral
{}
est remplacé par le nom de fichier et le littéral\;
est nécessaire pourfind
savoir que la commande personnalisée s'arrête là.ÉDITER:
(après la modification de votre question clarifiant ce que vous savez
-exec
)De
man xargs
:Notez que les noms de fichiers se terminant par des blancs vous causeraient des problèmes si vous utilisez
xargs
:Donc, si vous ne vous souciez pas de l'
-exec
option, vous feriez mieux d'utiliser-print0
et-0
:la source
-L 1
est la solution simple mais cela ne fonctionne pas si l'un des fichiers contient des espaces. Il s'agit d'une fonction clé de l'-print0
argument de find - pour séparer les arguments par le caractère «\ 0» au lieu d'espaces. Voici un exemple:Une meilleure solution consiste à
tr
convertir les sauts de ligne en caractères null (\0
), puis à utiliser l'xargs -0
argument. Voici un exemple:Si vous devez ensuite limiter le nombre d'appels, vous pouvez utiliser l'
-n 1
argument pour effectuer un appel au programme pour chaque entrée:Cela vous permet également de filtrer la sortie de find avant de convertir les ruptures en valeurs nulles.
la source
-L
est également qu'il n'autorise pas plusieurs arguments pour chaquexargs
appel de commande."?Une autre alternative ...
la source
Ces deux méthodes fonctionnent également et fonctionneront pour d'autres commandes qui n'utilisent pas find!
exemple d'utilisation:
supprimera tous les fichiers pyc de ce répertoire même si les fichiers pyc contiennent des espaces.
la source
est tout ce dont vous avez besoin.
la source
La commande suivante trouvera tous les fichiers (-type f) dans
/path
, puis les copiera en utilisantcp
dans le dossier actuel. Notez l'utilisation de if-I %
pour spécifier un caractère d'espace réservé dans lacp
ligne de commande afin que les arguments puissent être placés après le nom du fichier.find /path -type f -print0 | xargs -0 -I % cp % .
Testé avec xargs (GNU findutils) 4.4.0
la source
Vous pouvez limiter le nombre de lignes ou d'arguments (s'il y a des espaces entre chaque argument) à l'aide des indicateurs --max-lines ou --max-args, respectivement.
la source
Il semble que je n'ai pas assez de réputation pour ajouter un commentaire à la réponse de Tobia ci - dessus , donc j'ajoute cette "réponse" pour aider ceux d'entre nous qui veulent expérimenter de
xargs
la même manière sur les plates-formes Windows.Voici un fichier batch Windows qui fait la même chose que le script "show" codé rapidement de Tobia:
la source
Les réponses de @Draemon semblent correctes avec "-0" même avec de l'espace dans le fichier.
J'essayais la commande xargs et j'ai trouvé que "-0" fonctionnait parfaitement avec "-L". même les espaces sont traités (si l'entrée était terminée par null). Ce qui suit est un exemple :
Ce qui suit divisera les valeurs nulles et exécutera la commande sur chaque argument de la liste:
donc
-L1
exécutera l'argument sur chaque caractère nul terminé si elle est utilisée avec « -0 ». Pour voir la différence, essayez:même cela s'exécutera une fois:
La commande s'exécutera une fois car le "-L" ne se divise plus sur l'octet nul. vous devez fournir "-0" et "-L" pour fonctionner.
la source
Dans votre exemple, le fait de canaliser la sortie de find vers xargs est que le comportement standard de l'option -exec de find consiste à exécuter la commande une fois pour chaque fichier trouvé. Si vous utilisez find et que vous voulez son comportement standard, la réponse est simple - n'utilisez pas xargs pour commencer.
la source
find
, et c'est pourquoi ils ne préfèrent pas l'-exec
option.exécutez ant task clean-all sur chaque build.xml du dossier en cours ou du sous-dossier.
la source
ant
installé.