La situación es que tengo un reproductor de MP3 mpg321
que acepta una lista de archivos como argumento. Mantengo mi música en un directorio llamado "música", en el que hay algunos directorios más. Solo quiero jugar a todos, así que ejecuto el programa con
mpg321 $(find /music -iname "*\.mp3")
. El problema es que algunos nombres de archivos tienen espacios en blanco, y el programa divide esos nombres en partes más pequeñas y se queja de la falta de archivos. Envolviendo el resultado de find
entre comillas
mpg321 "$(find /music -iname "*\.mp3")"
no ayuda porque todo se convertirá en un gran "nombre de archivo", que obviamente no se encuentra.
¿Cómo puedo hacer esto entonces? Si eso es importante, lo estoy usando bash
, pero lo cambiaré zsh
pronto.
fuente
mpg321 $(find /music -iname "*\.mp3" -print0)
no?mpg321
no tiene nada que ver con eso, es el shell que está dividiendo la salidafind
en argumentos separados. Y-print0 | xargs -0
funcionará con todos los nombres de archivo posibles.Con GNU find, también puede usar
-print0
yxargs -0
, pero no tiene mucho sentido aprender otra herramienta más. La-exec ... {} +
sintaxis recibe poca mención porque Linux la adquirió más tarde-print0
, pero no hay razón para no usarla ahora.Con zsh o bash 4, esto es mucho más simple:
Solo en zsh, puede hacer que (parte de un) patrón no distinga entre mayúsculas y minúsculas:
fuente
Creo que la solución de Steven es la mejor, pero otra forma es usar la
-I
bandera de xargs , que le permite especificar una cadena que luego se reemplazará en el comando con el argumento (en lugar de simplemente agregar el argumento al final del comando). Puede usar eso para citar el argumento:fuente
-0
bandera de xargs sin encontrar-print0
. Además, la-I
bandera de xargs tiene una serie de consecuencias. A diferencia de simple,xargs
que comprimirá todas las líneas de stdin en un comando,xargs -I
se ejecutarámpg321
potencialmente cientos o miles de veces (una vez para cada archivo), lo que ciertamente no es la intención. También tenga en cuenta que citar a foo es innecesario, como loxargs
hace internamente. Observe que si comprime todos los nombres de archivo en la línea de línea y lo envíaxargs -I
, no se abrirán.Por lo general, es mejor hacerlo directamente,
-exec ${tgt_process} \{\} +
pero si necesita obtener una lista de nombres de archivo delimitada de manera confiable en un archivo o transmisiónfind
por cualquier razón, puede hacer esto:Lo que obtienes de eso son dos cadenas únicas . En la parte superior de cada nombre de archivo está la cadena
\n///
y en la cola de cada nombre de archivo está la cadena///\n
. Estas dos cadenas no aparecen en ningún otro lugar defind
la salida, excepto en esas posiciones, independientemente de los caracteres que contengan los nombres de archivo.Además, el uso anterior es POSIX de línea base portátil y se puede confiar en que funcione en casi cualquier sistema Unix. Esto no es cierto para el uso de un delimitador de byte nulo, a pesar de su conveniencia, recomendado por algunos otros.
Pero, de nuevo, esto sólo es necesario si se puede no directamente
-exec
a su$tgt_process
por cualquier razón, como que debe ser su objetivo. Por un lado, el método anterior aún requiere análisis. Por ejemplo, si desea que se cite cada shell de nombre de archivo, primero debe asegurarse de que se escapen las comillas en el nombre de archivo:Eso genera una matriz de nombres de archivo con escape de shell correctamente, independientemente de cuáles sean sus caracteres constitutivos. Ahora solo tiene que esperar que su aplicación en el extremo receptor no la destruya.
fuente
Otra forma de hacerlo es escapar de todos los caracteres especiales que aparecen en los nombres de archivo. P.ej:
Básicamente, esto pasará los nombres de archivo correctamente escapados a xargs para su ejecución y no habrá ningún problema.
fuente
sed 's|.|\\&|g'
: eso es lo que POSIX recomienda de todos modos.