La situación es que tengo un reproductor de MP3 mpg321que 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 findentre 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é zshpronto.
fuente

mpg321 $(find /music -iname "*\.mp3" -print0)no?mpg321no tiene nada que ver con eso, es el shell que está dividiendo la salidafinden argumentos separados. Y-print0 | xargs -0funcionará con todos los nombres de archivo posibles.Con GNU find, también puede usar
-print0yxargs -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
-Ibandera 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
-0bandera de xargs sin encontrar-print0. Además, la-Ibandera de xargs tiene una serie de consecuencias. A diferencia de simple,xargsque comprimirá todas las líneas de stdin en un comando,xargs -Ise ejecutarámpg321potencialmente 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 loxargshace 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ónfindpor 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 defindla 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
-execa su$tgt_processpor 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.