2009-10-30 14 views
70

que estaba esperando:Bash: copia el nombre de archivos de forma recursiva, la preservación de la estructura de carpetas

cp -R src/prog.js images/icon.jpg /tmp/package 

produciría una estructura simétrica en el directorio de destino:

/tmp 
| 
+-- package 
    | 
    +-- src 
    | | 
    | +-- prog.js 
    | 
    +-- images 
     | 
     +-- icon.jpg 

pero en cambio, ambos de los archivos se copian en/tmp/paquete. Una copia plana. (Esto está en OSX).

¿Hay una función bash simple que pueda usar para copiar todos los archivos, incluidos los archivos especificados por comodín (por ejemplo, src/*. Js) en su lugar correcto en el directorio de destino. Un poco como "para cada archivo, ejecute mkdir -p $(dirname "$file"); cp "$file" $(dirname "$file")", pero tal vez un solo comando.

This is a relevant thread, which suggests it's not possible. La solución del autor no es tan útil para mí, porque me gustaría simplemente proporcionar una lista de archivos, comodín o no, y tenerlos todos copiados en el directorio de destino. IIRC MS-DOS xcopy hace esto, pero parece que no hay equivalente para cp.

Respuesta

111

¿Has probado con la opción --parents? No sé si OS X lo admite, pero eso funciona en Linux.

cp --parents src/prog.js images/icon.jpg /tmp/package 

Si eso no funciona en OS X, intente

rsync -R src/prog.js images/icon.jpg /tmp/package 

como FIA sugeridos.

+0

bien, así que hablé demasiado pronto. Me gusta esta respuesta mejor. – EMPraptor

+3

gracias. resulta que "cp --parents" no es posible en mac, pero es bueno saber la bandera de otro unixen. rsync -R es la solución portátil más simple para este problema. – mahemoff

+1

Acepté este por su elegancia/memorabilidad, pero acabo de descubrir que esto no copia directorios completos (al menos en OSX), mientras que el tar que figura a continuación sí lo hace. – mahemoff

20

Una manera:

tar cf - <files> | (cd /dest; tar xf -) 
+0

Oh, me gusta esto mucho mejor que mi respuesta. – EMPraptor

+3

También puede usar la opción '-C' para hacer el chdir por usted -' tar cf - _files_ | tar -C/dest xf -' o algo así. –

+0

gracias, esto es conciso, aunque prefiero rsync por simplicidad. – mahemoff

1

TRY ...

for f in src/*.js; do cp $f /tmp/package/$f; done 

así que para lo que estaba haciendo ... originalmente

for f in `echo "src/prog.js images/icon.jpg"`; do cp $f /tmp/package/$f; done 

o

v="src/prog.js images/icon.jpg"; for f in $v; do cp $f /tmp/package/$f; done 
13

Alternativamente, si eres de la vieja escuela, utilice cpio:

cd /source; 
find . -print | cpio -pvdmB /target 

Claramente, puede filtrar la lista de archivos de contenido de su corazón.

La opción '-p' es para el modo 'paso' (en contra de '-i' para la entrada o '-o' para la salida). El '-v' es detallado (enumera los archivos a medida que se procesan). El '-m' conserva los tiempos de modificación. El '-B' significa usar 'bloques grandes' (donde los bloques grandes son 5120 bytes en lugar de 512 bytes); es posible que no tenga ningún efecto en estos días.

+0

¡la mejor respuesta para filtrar! gracias – milkplus

13

rsync's -R option va a hacer lo que usted espera. Es una copiadora de archivos con muchas funciones.Por ejemplo:

$ rsync -Rv src/prog.js images/icon.jpg /tmp/package/ 
images/ 
images/icon.jpg 
src/ 
src/prog.js 

sent 197 bytes received 76 bytes 546.00 bytes/sec 
total size is 0 speedup is 0.00 

resultados de la muestra:

$ find /tmp/package 
/tmp/package 
/tmp/package/images 
/tmp/package/images/icon.jpg 
/tmp/package/src 
/tmp/package/src/prog.js 
Cuestiones relacionadas