435 votes

Faire en sorte que xargs gère les noms de fichiers qui contiennent des espaces

$ ls *mp3 | xargs mplayer  

Playing Lemon.  
File not found: 'Lemon'  
Playing Tree.mp3.  
File not found: 'Tree.mp3'  

Exiting... (End of file)  

Ma commande échoue parce que le fichier "Lemon Tree.mp3" contient des espaces et donc xargs pense qu'il s'agit de deux fichiers. Puis-je faire en sorte que find + xargs fonctionnent avec des noms de fichiers comme celui-ci ?

0 votes

Au lieu de ls |grep mp3 |sed -n "7p" vous pouvez simplement utiliser echo "Lemon Tree.mp3" .

0 votes

Cette question trouve également une réponse dans stackoverflow.com/a/33528111/94687

484voto

Ray Points 126

Le site xargs prend les caractères d'espace blanc (tabulations, espaces, nouvelles lignes) comme délimiteurs.

Vous pouvez limiter la recherche aux caractères de la nouvelle ligne ('). \n ) avec -d option comme ceci :

ls *.mp3 | xargs -d '\n' mplayer

Il ne fonctionne qu'avec GNU xargs.

Pour MacOS :

ls *.mp3 | tr \\n \\0 | xargs -0 mplayer

L'approche la plus simpliste et la plus utile en pratique (lorsqu'il n'est pas nécessaire de traiter les noms de fichiers plus avant) :

mplayer *.mp3

267voto

Jens Points 17702

L'utilitaire xargs lit les chaînes délimitées par des espaces, des tabulations, des nouvelles lignes et des fins de fichiers à partir de l'entrée standard et exécute l'utilitaire avec les chaînes comme arguments.

Il faut éviter d'utiliser l'espace comme délimiteur. Ceci peut être fait en changeant le délimiteur pour xargs. Selon le manuel :

 -0      Change xargs to expect NUL (``\0'') characters as separators,
         instead of spaces and newlines.  This is expected to be used in
         concert with the -print0 function in find(1).

Par exemple :

 find . -name "*.mp3" -print0 | xargs -0 mplayer

Pour répondre à la question sur la lecture du septième mp3, il est plus simple d'exécuter

 mplayer "$(ls *.mp3 | sed -n 7p)"

12 votes

Il s'agit d'utiliser GNU find et GNU xargs toutes les versions de ces programmes ne prennent pas en charge ces options (bien qu'il y ait des raisons de penser qu'elles le devraient).

1 votes

@JonathanLeffler s/GNU/FreeBSD/g ; POSIX a malheureusement peur des caractères NUL dans les fichiers texte et n'a pas encore eu assez de thérapie :-) Mon conseil a en fait recours à des options non portables.

8 votes

Et Mac OS X (un dérivé de BSD) a find con -print0 y xargs con -0 . AFAIK, HP-UX, AIX et Solaris ne le font pas, cependant (mais je peux être corrigé : HP-UX 11i ne le fait pas ; Solaris 10 ne le fait pas ; AIX 5.x ne le fait pas ; mais il ne s'agit pas des versions actuelles). Il ne serait pas difficile de modifier sed par exemple, pour utiliser des "lignes" se terminant par '\0' au lieu de '\n' et la norme POSIX 2008 getdelim() le rendrait facile à gérer.

35voto

Scott Wilson Points 5160

Essayez

find . -name \*.mp3 -print0 | xargs -0 mplayer

au lieu de

ls | grep mp3

28voto

Graeme Pyle Points 1218

Xargs sur MacOS n'a pas l'option -d, donc cette solution utilise -0 à la place.

Demander à ls de sortir un fichier par ligne, puis traduire les newlines en nulls et dire à xargs d'utiliser les nulls comme délimiteur :

ls -1 *mp3 | tr "\n" "\0" | xargs -0 mplayer

18voto

Juan Points 94

La réponse de Dick.Guertin [1], qui suggère d'échapper aux espaces dans un nom de fichier, est une alternative intéressante aux autres solutions proposées ici (comme l'utilisation d'un caractère nul comme séparateur plutôt qu'un espace). Mais cela pourrait être plus simple - vous n'avez pas vraiment besoin d'un caractère unique. Vous pouvez simplement demander à sed d'ajouter directement les espaces échappés :

ls | grep ' ' | sed 's| |\\ |g' | xargs ...

De plus, le grep n'est nécessaire que si vous uniquement veulent des fichiers avec des espaces dans les noms. De manière plus générale (par exemple, lors du traitement d'un lot de fichiers dont certains ont des espaces, d'autres non), il suffit de sauter le grep :

ls | sed 's| |\\ |g' | xargs ...

Ensuite, bien sûr, le nom du fichier peut comporter d'autres espaces que les blancs (par exemple, une tabulation) :

ls | sed -r 's|[[:blank:]]|\\\1|g' | xargs ...

Cela suppose que vous avez un sed qui supporte -r (regex étendu) comme GNU sed ou les versions récentes de bsd sed (e.g., FreeBSD qui épelait à l'origine l'option "-E" avant FreeBSD 8 et supporte à la fois -r & -E pour la compatibilité jusqu'à FreeBSD 11 au moins). Sinon, vous pouvez utiliser une expression entre crochets de classe de caractères regex de base et entrer manuellement les caractères espace et tabulation dans le champ [] délimiteurs.

[1] Il serait peut-être plus approprié de commenter ou de modifier cette réponse, mais pour l'instant je n'ai pas assez de réputation pour commenter et je ne peux que suggérer des modifications. Puisque les dernières formes ci-dessus (sans le grep) modifient le comportement de la réponse originale de Dick.Guertin, une édition directe n'est peut-être pas appropriée de toute façon.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X