La situation est, j'ai un lecteur MP3 mpg321
qui accepte une liste de fichiers comme argument. Je garde ma musique dans un répertoire nommé "musique", dans lequel il y a quelques autres répertoires. Je veux juste les jouer tous, donc je lance le programme avec
mpg321 $(find /music -iname "*\.mp3")
. Le problème est que certains noms de fichiers contiennent des espaces, et le programme divise ces noms en parties plus petites et se plaint des fichiers manquants. Envelopper le résultat de find
entre guillemets
mpg321 "$(find /music -iname "*\.mp3")"
n'aide pas car tout deviendra un grand "nom de fichier", qui est évidemment introuvable.
Comment puis-je faire cela alors? Si cela importe, j'utilise bash
, mais je passerai zsh
bientôt.
la source
mpg321 $(find /music -iname "*\.mp3" -print0)
pas?mpg321
n'a rien à voir avec ça, c'est le shell qui décompose la sortie defind
en arguments séparés. Et-print0 | xargs -0
fonctionnera avec tous les noms de fichiers possibles.Avec GNU find, vous pouvez également utiliser
-print0
etxargs -0
, mais cela ne sert à rien d'apprendre un autre outil. La-exec ... {} +
syntaxe est peu mentionnée car Linux l'a acquise plus tard-print0
, mais il n'y a aucune raison de ne pas l'utiliser maintenant.Avec zsh ou bash 4, c'est beaucoup plus simple:
Dans zsh uniquement, vous pouvez rendre un (partie d'un) motif insensible à la casse:
la source
Je pense que la solution de Steven est la meilleure, mais une autre façon consiste à utiliser le
-I
drapeau de xargs , qui vous permet de spécifier une chaîne qui sera ensuite remplacée dans la commande par l'argument (au lieu de simplement ajouter l'argument à la fin de la commande). Vous pouvez l'utiliser pour citer l'argument:la source
-0
drapeau de xargs sans trouver-print0
. De plus, le-I
drapeau de xargs a un certain nombre de conséquences. Contrairement à tout simplementxargs
qui compressera toutes les lignes de stdin en une seule commande,xargs -I
s'exécuterampg321
potentiellement des centaines ou des milliers de fois (une fois pour chaque fichier), ce qui n'est certainement pas l'intention. Gardez également à l'esprit qu'il n'est pas nécessaire de citer foo, tout commexargs
cela en interne. Notez que si vous compressez tous les noms de fichiers sur la ligne et que vous les envoyezxargs -I
, ils ne s'ouvriront pas.Il est généralement préférable de le faire directement,
-exec ${tgt_process} \{\} +
mais si vous avez besoin d'obtenir une liste de noms de fichiers délimitée de manière fiable dans un fichier ou un fluxfind
pour une raison quelconque, vous pouvez le faire:Ce que vous en retirez, ce sont deux chaînes uniques . En tête de chaque nom de fichier se trouve la chaîne
\n///
et à la fin de chaque nom de fichier se trouve la chaîne///\n
. Ces deux chaînes n'apparaissent nulle part ailleurs dansfind
la sortie de, à l'exception de ces positions, quels que soient les caractères contenus dans les noms de fichiers.En outre, l'utilisation ci-dessus est portable POSIX de base et peut être utilisée pour fonctionner sur presque tous les systèmes Unix. Ce n'est pas le cas de l'utilisation d'un délimiteur d'octets nuls - malgré sa commodité - recommandé par certains autres.
Mais, encore une fois, cela n'est nécessaire que si vous ne pouvez pas directement le
-exec
faire$tgt_process
pour une raison quelconque, car cela devrait être votre objectif. D'une part, la méthode ci-dessus nécessite toujours l'analyse. Par exemple, si vous voulez que chaque shell de nom de fichier soit cité, vous devez d'abord vous assurer que les guillemets durs dans le nom de fichier ont été échappés:Cela génère un tableau de noms de fichiers correctement échappés du shell, quels que soient leurs caractères constitutifs. Il ne vous reste plus qu'à espérer que votre application côté réception ne la gâchera pas.
la source
Une autre façon de procéder consiste à échapper à tous les caractères spéciaux qui se trouvent dans vos noms de fichiers. Par exemple:
Cela passera essentiellement les noms de fichiers correctement échappés à xargs pour exécution et il n'y aura aucun problème.
la source
sed 's|.|\\&|g'
- c'est ce que POSIX recommande de toute façon.