Estoy tratando de ejecutar un comando similar al siguiente en un script bash. Debe buscar a través de todas las subcarpetas $sourcediry 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 $2a-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 xargso 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 -execcomando. 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

xargspor 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
NULLcomo separadorfuente
-print0afindy-0axargsNULLno es necesario si lo usa'{}', es importante cuando no lo hace. El beneficio real entre uno de otro, aparte delPOSIXcumplimiento, 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
$targetdiry luego usar el parámetro especial$0dentro 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
shque 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-print0y-0.fuente
xargs. El mayor ejemplo, ¿qué pasa si no está encontrando archivos? Uso xargs en lugar deforbucles generales todo el tiempo,findes mucho más pequeño en alcance. Además,findsolo admite que+si está utilizando GNUfind, no está definido en POSIX. Entonces, si bien debe sentirse libre de preferirfindsolo, no hace todo lo que hace xargs. Cuando consideras GNUxargstambién obtienes lo-Pque hace multi-core. Vale la pena aprender de todosxargsmodos.fuente