it-swarm-es.tech

¿Cómo pasar el resultado de "buscar" como una lista de archivos?

La situación es que tengo un reproductor MP3 mpg321 que acepta una lista de archivos como argumento. Guardo mi música en un directorio llamado "música", en el que hay algunos directorios más. Solo quiero reproducirlos 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 que faltan 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 importa, estoy usando bash, pero pronto cambiaré a zsh.

11
phunehehe

Intente usar la opción -print0 O -printf De find en combinación con xargs así:

find /music -iname "*\.mp3" -print0 | xargs -0 mpg321

Cómo funciona esto se explica por página del manual de búsqueda :

-print0

Cierto; imprime el nombre completo del archivo en la salida estándar, seguido de un carácter nulo (en lugar del carácter de nueva línea que usa -print). Esto permite que los programas que procesan la salida de búsqueda interpreten correctamente los nombres de archivo que contienen nuevas líneas u otros tipos de espacios en blanco. Esta opción corresponde a la opción -0 de xargs.

17
Steven D
find /music -iname "*\.mp3" -exec mpg123 {} +

Con GNU buscar, también puede usar -print0 y xargs -0 , pero no tiene mucho sentido aprender otra herramienta. Los -exec ... {} + la sintaxis recibe poca mención porque Linux la adquirió después de -print0, pero no hay razón para no usarlo ahora.

Con zsh o bash 4, esto es mucho más simple:

mpg123 **/*.[Mm][Pp]3

Solo en zsh, puede hacer que un patrón (parte de un) no distinga entre mayúsculas y minúsculas:

mpg123 (#i)**/*.mp3

Creo que la solución de Steven es la mejor, pero otra forma es usar xargs '-I bandera, que le permite especificar una cadena que luego será reemplazada en el comando con el argumento (en lugar de simplemente agregar el argumento al final del comando). Puedes usar eso para citar el argumento:

find /music -iname "*\.mp3" | xargs -0 -Ifoo mpg321 "foo"
2
Michael Mrozek

Por lo general, es mejor directamente -exec ${tgt_process} \{\} + pero si lo hace necesita para obtener una lista delimitada de manera confiable de nombres de archivo en un archivo o flujo de find por cualquier razón, entonces puede hacer esto:

find -exec sh -c 'printf "///%s///\n" "[email protected]"' -- \{\} +

Lo que obtienes de eso son dos únicas cadenas. A la cabeza de cada nombre de archivo está la cadena \n/// y al final de cada nombre de archivo está la cadena ///\n. Estas dos cadenas no aparecen en ningún otro lugar de la salida de find excepto en esas posiciones, independientemente de los caracteres que contengan los nombres de archivo.

Además, el uso anterior es portátil POSIX básico y se puede confiar en que funcionará en casi cualquier sistema Unix. Esto no se aplica al uso de un delimitador de bytes nulos, a pesar de su conveniencia, recomendado por otros.

Pero, de nuevo, esto solo es necesario si no puede -exec tu $tgt_process por el motivo que sea, ya que ese debería ser su objetivo. Por un lado, el método anterior todavía requiere análisis. Por ejemplo, si quisiera que Shell cite cada nombre de archivo, primero debe asegurarse de que se hayan escapado las comillas en el nombre del archivo:

find ... + | sed 's|'\''|&"&"&|g;s|///|'\''|g'

Eso genera una matriz de nombres de archivo con el escape de Shell adecuado independientemente de los caracteres que los componen. Ahora solo tiene que esperar que su aplicación en el extremo receptor no la estropee.

1
mikeserv

Otra forma de hacer esto es escapar de todos los caracteres especiales que vienen en los nombres de sus archivos. P.ej.:

find /music -iname "*\.mp3" | sed 's!\([] \*\$\/&[]\)!\\\1!g' | xargs mpg321

Básicamente, esto pasará los nombres de los archivos correctamente escapados a xargs para su ejecución y no habrá ningún problema.

0
Priyabrata Patnaik