txt texto script por mover extension copiar como buscar archivos archivo shell find xargs

shell - texto - ¿Cómo puedo hacer que xargs maneje nombres de archivos que contienen espacios?



mover archivos por extension linux (12)

Dado el título específico de esta publicación, esta es mi sugerencia:

ls | grep '' '' | tr '' '' ''<'' | sed ''s|<|// |g''

La idea es convertir espacios en blanco a cualquier carácter único, como ''<'', y luego cambiarlo a ''/', una barra invertida seguida de un espacio en blanco. A continuación, puede canalizarlo en cualquier comando que desee, como por ejemplo:

ls | grep '' '' | tr '' '' ''<'' | sed ''s|<|// |g'' | xargs -L1 GetFileInfo

La clave aquí radica en los comandos ''tr'' y ''sed''; y puedes usar cualquier caracter además de ''<'', como ''?'' o incluso un tab-character.

$ ls *mp3 | xargs mplayer Playing Lemon. File not found: ''Lemon'' Playing Tree.mp3. File not found: ''Tree.mp3'' Exiting... (End of file)

Mi comando falla porque el archivo "Lemon Tree.mp3" contiene espacios y por eso xargs piensa que son dos archivos. ¿Puedo hacer que find + xargs funcione con nombres de archivos como este?


Depende de (a) qué tan apegado está al número 7 en comparación con, por ejemplo, limones, y (b) si alguno de sus nombres de archivo contiene líneas nuevas (y si está dispuesto a cambiarles el nombre si lo hacen).

Hay muchas maneras de manejarlo, pero algunos de ellos son:

mplayer Lemon*.mp3 find . -name ''Lemon*.mp3'' -exec mplayer {} '';'' i=0 for mp3 in *.mp3 do i=$((i+1)) [ $i = 7 ] && mplayer "$mp3" done for mp3 in *.mp3 do case "$mp3" in (Lemon*) mplayer "$mp3";; esac done i=0 find . -name *.mp3 | while read mp3 do i=$((i+1)) [ $i = 7 ] && mplayer "$mp3" done

El ciclo de read no funciona si los nombres de archivo contienen líneas nuevas; los otros funcionan correctamente incluso con nuevas líneas en los nombres (sin mencionar los espacios). Por mi dinero, si tiene nombres de archivos que contienen una nueva línea, debe cambiar el nombre del archivo sin la nueva línea. Usar las comillas dobles alrededor del nombre del archivo es la clave para que los bucles funcionen correctamente.

Si tiene GNU find y GNU xargs (o FreeBSD (* BSD?), O Mac OS X), también puede usar las opciones -print0 y -0 , como en:

find . -name ''Lemon*.mp3'' -print0 | xargs -0 mplayer

Esto funciona independientemente del contenido del nombre (los dos únicos caracteres que no pueden aparecer en un nombre de archivo son barra inclinada y NUL, y la barra no causa problemas en la ruta del archivo, por lo que usar NUL como delimitador de nombre lo cubre todo). Sin embargo, si necesita filtrar las primeras 6 entradas, necesita un programa que maneje ''líneas'' terminadas por NUL en lugar de línea nueva ... y no estoy seguro de que haya alguna.

El primero es de lejos el más simple para el caso específico en la mano; sin embargo, es posible que no se generalice para cubrir sus otros escenarios que aún no ha enumerado.


El comando xargs toma caracteres de espacio en blanco (pestañas, espacios, nuevas líneas) como delimitador. Puede restringirlo solo para los nuevos caracteres de línea (''/ n'') con la opción -d como esta:

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

Funciona solo con GNU xargs. Para sistemas BSD, use la opción -0 como esta:

ls *.mp3 | xargs -0 mplayer

Este método es más simple y también funciona con los xargs de GNU.


En macOS 10.12.x, si tiene espacios en nombres de archivos o subdirectorios, puede usar lo siguiente:

find . -name ''*.swift'' -exec echo ''"{}"'' /; |xargs wc -l


Esta es una publicación anterior, pero las soluciones alternativas pueden ser útiles ...

También puede agregar un carácter nulo al final de sus líneas usando Perl, luego use la opción -0 en xargs. A diferencia de xargs -d ''/ n'' (en respuesta aprobada), esto funciona en todas partes, incluido OSX.

Por ejemplo, para enumerar recursivamente (ejecutar, mover, etc.) imágenes jpg que pueden contener espacios u otros personajes divertidos, usaría:

find . | grep /.jpg | perl -ne ''chop; print "$_/0"'' | xargs -0 ls

(Nota: para el filtrado, prefiero la sintaxis "| grep" más fácil de recordar a los argumentos "find" --name).


La respuesta de Dick.Guertin [1] sugirió que uno podría escapar de los espacios en un nombre de archivo es una alternativa valiosa a otras soluciones sugeridas aquí (como usar un carácter nulo como separador en lugar de espacio en blanco). Pero podría ser más simple: realmente no necesitas un personaje único. Puedes simplemente agregar los espacios de escape directamente:

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

Además, grep solo es necesario si solo deseas archivos con espacios en los nombres. De forma más genérica (por ejemplo, al procesar un lote de archivos, algunos de los cuales tienen espacios, otros no), simplemente omita el grep:

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

Entonces, por supuesto, el nombre del archivo puede tener otros espacios en blanco que espacios en blanco (por ejemplo, una pestaña):

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

Eso supone que tiene un sed que admite -r (expresión regular extendida) como GNU sed o versiones recientes de bsd sed (por ejemplo, FreeBSD que originalmente deletreó la opción "-E" antes de FreeBSD 8 y admite tanto -r como -E para compatibilidad a través de FreeBSD 11 al menos). De lo contrario, puede usar una expresión de corchete de clase de caracteres regex básica e ingresar manualmente los caracteres de espacio y tabulación en los delimitadores [] .

[1] Esto es quizás más apropiado como un comentario o una edición de esa respuesta, pero por el momento no tengo suficiente reputación para comentar y solo puedo sugerir ediciones. Dado que este último forma arriba (sin el grep) altera el comportamiento de la respuesta original de Dick .Guertin, una edición directa quizás no sea apropiada de todos modos.


La utilidad xargs lee cadenas delimitadas de espacio, pestaña, nueva línea y fin de archivo desde la entrada estándar y ejecuta la utilidad con las cadenas como argumentos.

Desea evitar el uso de espacio como delimitador. Esto se puede hacer cambiando el delimitador para xargs. De acuerdo con el manual:

-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).

Como:

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

Para responder la pregunta sobre jugar cada séptimo mp3; es más simple de ejecutar

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


Tratar

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

en lugar de

ls | grep mp3


xargs en MacOS no tiene la opción -d, por lo que esta solución usa -0 en su lugar.

Obtenga ls para generar un archivo por línea, luego convierta las líneas nuevas en nulos y diga a xargs que use nulos como delimitador:

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


ls | grep mp3 | sed -n "7p" | xargs -i mplayer {}

Tenga en cuenta que en el comando anterior, xargs llamará a mplayer nuevo para cada archivo. Esto puede ser indeseable para mplayer , pero puede estar bien para otros objetivos.


Sé que no estoy respondiendo la pregunta de xargs directamente, pero vale la pena mencionar la opción -exec s -exec .

Dado el siguiente sistema de archivos:

[root@localhost bokeh]# tree --charset assci bands bands |-- Dream/ Theater |-- King''s/ X |-- Megadeth `-- Rush 0 directories, 4 files

El comando find se puede hacer para manejar el espacio en Dream Theater y King''s X. Entonces, para encontrar a los bateristas de cada banda usando grep:

[root@localhost]# find bands/ -type f -exec grep Drums {} + bands/Dream Theater:Drums:Mike Mangini bands/Rush:Drums: Neil Peart bands/King''s X:Drums:Jerry Gaskill bands/Megadeth:Drums:Dirk Verbeuren

En la opción -exec {} representa el nombre de archivo incluida la ruta. Tenga en cuenta que no tiene que escapar ni ponerlo entre comillas.

La diferencia entre los terminadores de -exec ( + y /; ) es que + agrupa tantos nombres de archivos como puede en una línea de comando. Considerando que /; ejecutará el comando para cada nombre de archivo.

Por lo tanto, find bands/ -type f -exec grep Drums {} + dará como resultado:

grep Drums "bands/Dream Theater" "bands/Rush" "bands/King''s X" "bands/Megadeth"

y find bands/ -type f -exec grep Drums {} /; resultará en:

grep Drums "bands/Dream Theater" grep Drums "bands/Rush" grep Drums "bands/King''s X" grep Drums "bands/Megadeth"

En el caso de grep esto tiene el efecto secundario de imprimir el nombre de archivo o no.

[root@localhost bokeh]# find bands/ -type f -exec grep Drums {} /; Drums:Mike Mangini Drums: Neil Peart Drums:Jerry Gaskill Drums:Dirk Verbeuren [root@localhost bokeh]# find bands/ -type f -exec grep Drums {} + bands/Dream Theater:Drums:Mike Mangini bands/Rush:Drums: Neil Peart bands/King''s X:Drums:Jerry Gaskill bands/Megadeth:Drums:Dirk Verbeuren

Por supuesto, las opciones de grep -h y -H controlarán si el nombre de archivo se imprime independientemente de cómo se llama grep .

xargs

xargs también puede controlar cómo están los archivos man en la línea de comando.

xargs agrupa por defecto todos los argumentos en una línea. Para hacer lo mismo que -exec /; usa xargs -l . Tenga en cuenta que la opción -t le dice a xargs que imprima el comando antes de ejecutarlo.

[root@localhost bokeh]# find ./bands -type f | xargs -d ''/n'' -l -t grep Drums grep Drums ./bands/Dream Theater Drums:Mike Mangini grep Drums ./bands/Rush Drums: Neil Peart grep Drums ./bands/King''s X Drums:Jerry Gaskill grep Drums ./bands/Megadeth Drums:Dirk Verbeuren

Observe que la opción -l le dice a xargs que ejecute grep para cada nombre de archivo.

En comparación con el valor predeterminado (es decir, no -l opción):

[root@localhost bokeh]# find ./bands -type f | xargs -d ''/n'' -t grep Drums grep Drums ./bands/Dream Theater ./bands/Rush ./bands/King''s X ./bands/Megadeth ./bands/Dream Theater:Drums:Mike Mangini ./bands/Rush:Drums: Neil Peart ./bands/King''s X:Drums:Jerry Gaskill ./bands/Megadeth:Drums:Dirk Verbeuren

xargs tiene un mejor control sobre cuántos archivos pueden estar en la línea de comando. Dale a la opción -l la cantidad máxima de archivos por comando.

[root@localhost bokeh]# find ./bands -type f | xargs -d ''/n'' -l2 -t grep Drums grep Drums ./bands/Dream Theater ./bands/Rush ./bands/Dream Theater:Drums:Mike Mangini ./bands/Rush:Drums: Neil Peart grep Drums ./bands/King''s X ./bands/Megadeth ./bands/King''s X:Drums:Jerry Gaskill ./bands/Megadeth:Drums:Dirk Verbeuren [root@localhost bokeh]#

Ver que grep se ejecutó con dos nombres de archivo debido a -l2 .


find . -name ''Lemon*.mp3'' -print0 | xargs -­0 -i mplayer ''{}''

Esto ayudó en mi caso a eliminar diferentes archivos con espacios. Debería funcionar también con mplayer. El truco necesario son las cotizaciones. (Testet en Linux xubuntu 14.04)