Estoy tratando de ejecutar un comando similar al siguiente en un script bash. Debe buscar a través de todas las subcarpetas $sourcedir
y copiar todos los archivos de cierto tipo al nivel raíz de $targetdir
.
#!/bin/bash
# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;
Esto parece estar bastante cerca, excepto que {}
no se pasa en cuanto $2
a-exec sh -c ...
Me gustaría hacer esto lo más cerca posible de la "manera correcta", con tolerancia para caracteres especiales en nombres de archivo (específicamente caracteres de comillas simples).
Editar: veo gente sugiriendo usar xargs
o encadenar argumentos. Tenía la impresión de que esto solo está bien para un número limitado de argumentos. Si tengo, por ejemplo, miles de archivos .jpg que intento copiar de varios directorios de galería en un directorio de presentación de diapositivas gigante, ¿seguirán funcionando las soluciones que encadenan argumentos?
Edición 2: mi problema era que faltaba un _
antes de mi primera opción para sh en el -exec
comando. Para cualquiera que tenga curiosidad sobre cómo hacer que el comando find funcione, agregue _
y todo estará bien:
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;
Sin embargo, he aceptado una respuesta a continuación porque cumple la misma tarea, pero es más eficiente y elegante.
fuente
xargs
por la que alguna vez se creó, para manejar automáticamente grandes cantidades de argumentos en comandos regulares que tenían límites. También a tener en cuenta, la mayoría de los límites máximos de argumentos, se han mejorado enormemente para las utilidades GNU estándar. También verá un beneficio de rendimiento, evitando todas esas bifurcaciones de proceso, que en miles de archivos es relevante.Respuestas:
¿Desea copiar archivos de un tipo específico a un directorio específico? Esto se hace mejor con
xargs
, y ni siquiera lo necesitassh
. Esta es una forma más apropiada de hacerlo, también debería ejecutarse de manera más eficiente.Si necesita manejar nombres de archivo especiales, utilícelos
NULL
como separadorfuente
-print0
afind
y-0
axargs
NULL
no es necesario si lo usa'{}'
, es importante cuando no lo hace. El beneficio real entre uno de otro, aparte delPOSIX
cumplimiento, es el rendimiento.Debe pasar
{}
como argumento al shell y luego recorrer cada arg.Nota : La forma en que esto funciona es que el primer argumento para un shell es el nombre del shell , podemos explotar esto pasando el nombre como
$targetdir
y luego usar el parámetro especial$0
dentro del script del shell para acceder a ese targetdir.fuente
"$targetdir"
no se expande entre comillas simples.Si no crees en la iglesia de xargs:
Explicación:
copia b, cyd al directorio de destino a.
invoca el comando en un gran grupo de archivos a la vez, no uno tras otro (que es estándar, si lo usa en
";"
lugar de+
). Es por eso que tiene que tirar del targetdir al frente y marcarlo explícitamente como objetivo.Esto funciona para gnu-find y podría no ser para otras implementaciones de find. Por supuesto, también se basa en la bandera -t.
TechZilla, por supuesto, está en el extremo derecho, ya
sh
que no es necesario invocar cp.Si no lo usa
xargs
, lo cual es innecesario en la mayoría de los casos en combinaciónfind
, se salvará de aprender el indicador-print0
y-0
.fuente
xargs
. El mayor ejemplo, ¿qué pasa si no está encontrando archivos? Uso xargs en lugar defor
bucles generales todo el tiempo,find
es mucho más pequeño en alcance. Además,find
solo admite que+
si está utilizando GNUfind
, no está definido en POSIX. Entonces, si bien debe sentirse libre de preferirfind
solo, no hace todo lo que hace xargs. Cuando consideras GNUxargs
también obtienes lo-P
que hace multi-core. Vale la pena aprender de todosxargs
modos.fuente