Différence entre «xargs» et substitution de commande?

14

Dans de nombreux cas, j'utilise la substitution de commandes au lieu de xargs. Par exemple, rm $(ls)c'est la même chose quels | xargs rm

Quelles sont vraiment les différences entre eux?

Je pense que l'une des différences est que la substitution de commandes s'exécute en sous-shell tout en xargss'exécute dans le shell actuel, mais je ne suis pas sûr.

Veuillez énumérer les différences.

Sinoosh
la source

Réponses:

9

Une différence est que lorsque vous utilisez la substitution de commandes au lieu d'un canal, la taille des données transmises est limitée par la taille du tampon de commande, elle est donc tronquée dans certains cas sans avertissement. Cela signifie également que toute la sortie de la commande doit être produite et stockée en mémoire avant d'être passée à la commande suivante, donc pour les grandes sorties, vous pouvez utiliser beaucoup plus de mémoire que nécessaire.

Un autre problème avec la première méthode est que la sortie est divisée en espaces blancs, vous ne pouvez donc pas gérer les noms de fichiers contenant des espaces. xargsest également affecté par le problème des espaces, mais il peut être résolu en modifiant le délimiteur utilisé. Pour gérer correctement les noms de fichiers, vous devez utiliser l'octet nul comme délimiteur dans le deuxième exemple.

Un troisième problème est que les globes sont développés, donc si un fichier a des astérisques ou des points d'interrogation dans son nom, il y aura des résultats inattendus.

Vous pouvez trouver une discussion intéressante sur le problème ici: http://mywiki.wooledge.org/ParsingLs

La syntaxe correcte serait

echo rm *

ou si vous devez utiliser xargs,

find . -maxdepth 1 -print0 | xargs -0 echo rm

Supprimer echolorsque la sortie semble correcte.

user000001
la source
1
@Sinoosh: xargss'exécute également dans un sous-shell en raison du canal, sauf si vous l'activez shopt -s lastpipe, auquel cas il s'exécutera dans le shell actuel. Je ne pense pas que l'exécution en sous-shell soit un problème dans ce cas, car vous ne modifiez aucune variable.
user000001
1
@Sinoosh: Pour passer des arguments un par un, vous pouvez utiliser le -ldrapeau, comme find . -maxdepth 1 -print0 | xargs -0 -l rm. Pour la deuxième question, vous ne pouvez pas utiliser lsavecxargs -0 car ls ne divise pas la sortie sur le bute nul, mais avec des sauts de ligne (qui sont valides dans les noms de fichiers BTW)
user000001
1
@Sinoosh: Pas le premier paragraphe, mais le second: xargs sans l' -0option souffre du problème des espaces blancs.
user000001
1
Lire man xargs, utiliser echopour les tests, non rm. xargsnous permet de dépasser les limites du shell (certains tampons sont limités à 65 Ko, une liste de noms de fichiers ne l'est pas).
waltinator
1
@Sinoosh: Je n'ai pas de bonne référence à portée de main, mais vous pouvez taper xargs --show-limitset vous verrez la limite qui est définie sur votre système,
user000001