Copie el tipo de archivo específico manteniendo la estructura de la carpeta

108

Tengo una estructura de carpetas con un montón de archivos * .csv dispersos por las carpetas. Ahora quiero copiar todos los archivos * .csv a otro destino manteniendo la estructura de carpetas.

Funciona haciendo:

cp --parents *.csv /target
cp --parents */*.csv" /target
cp --parents */*/*.csv /target
cp --parents */*/*/*.csv /target
...

y así sucesivamente, pero me gustaría hacerlo usando un comando.

Wilfred Hughes
fuente

Respuestas:

126

¿Hay alguna razón por la cual las personas se resisten a usar los hallazgos -exec? Es muy útil.

find . -name '*.csv' -exec cp --parents \{\} /target \;

Conoce tus herramientas. ;-)

msb
fuente
62
Probablemente por esto \ {\} \;
igo
12
'{}'funciona igual de bien
OrangeDog
3
Aunque -execdires más seguro que -exec, simplemente reemplazar uno con el otro no conserva la estructura de la carpeta como se esperaba.
Simon Shine
2
¿Por qué recibo el mensaje 'Omitiendo directorio' cuando intento copiarlos con su comando?
Vicky Dev
44
¿Puedes explicar por qué los frenos deben escaparse aquí?
Noumenon
47

También podrías usar rsyncpara esto.

$ rsync -a --prune-empty-dirs --include '*/' --include '*.csv' --exclude '*' source/ target/

Si desea mantener directorios vacíos del árbol de origen, omita la --prune-empty-dirsopción:

$ rsync -a --include '*/' --include '*.csv' --exclude '*' source/ target/

Si no desea que se conserven enlaces simbólicos, fechas de modificación, permisos de archivos, propietarios, etc., reemplácelos -acon otra combinación de -rlptgoD. ;-)

Dubu
fuente
1
-mes un acceso directo para --prune-emty-dirs.
Geremia
Además, -Rse puede agregar la opción para copiar la estructura del directorio principal de origen. (cf. mi respuesta aquí.)
Geremia
-R funciona para mi! Gracias
gigi2
32

Puede usar find y cpio en modo de paso

find . -name '*.csv' | cpio -pdm  /target

Esto encontrará todos los archivos .csv en el directorio actual y debajo, y los copiará en / target manteniendo la estructura del directorio enraizada ..

Si utiliza

find /path/to/files -name '*.csv' | cpio -pdm /target

encontrará todo el archivo en /path/to/filesy debajo y los copiará en /target/path/to/filesy debajo.


fuente
3
Intenté todas las respuestas hasta esta, y esta fue la única que funcionó en el primer intento
OscarRyz
21

El cpcomando permite múltiples argumentos de origen:

cp **/*.csv --parents ../target

CAVEAT: Estoy usando un globo recursivo aquí; Esta es la globstaropción en Bash 4+ y ksh, y es compatible por defecto en zsh. Los globos recursivos no coinciden con los archivos y carpetas ocultos, y algunas implementaciones siguen enlaces simbólicos mientras que otras no .

Si su caparazón no admite globos recursivos, o si prefiere no usarlos, puede hacer lo siguiente:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - esto es, por supuesto, muy redundante y requiere saber cuán profunda es la estructura de su directorio.
  • $(find . -name '*.csv')- Esto va a coincidir con los archivos y carpetas ocultos. findtambién admite especificar si se siguen o no los enlaces simbólicos, lo que puede ser útil.
Kyle Strand
fuente
esto es exactamente lo que probé (el globo recursivo) y encontró algunos pero no todos. bastante raro. Obtuve el mismo resultado exacto cuando utilicé el script npm copyfiles pero si uso el comando find lo encuentra todo ...
Randyaa
@Randyaa Necesitaré más detalles sobre qué archivos, exactamente, no se encontraron para poder ayudarte. Puede encontrar la discusión aquí y continuar aquí sobre el comportamiento preciso del globo recursivo útil.
Kyle Strand
1
Resulta que el globo recursivo no estaba habilitado por alguna razón ... Nunca me he encontrado con esto antes, pero lo corregí con solo una ejecución shopt -s globstarinmediatamente antes de mi comando y todo está bien. ¡Gracias por el seguimiento!
Randyaa
--parentsera lo que estaba buscando gracias
Josh
17

Este funcionó para mí:

find -name "*.csv" | xargs cp --parents -t /target

marko
fuente
La mejor respuesta con la sintaxis más simple. Funciona bien y es fácil de recordar. En muchos casos find [things] | xargs [do stuff]es muy poderoso.
Todos los días astronauta
Convenido. Muy sencillo en comparación con algunas de las otras respuestas.
Tim B
1
Se rompe si tienes espacios en los nombres de archivo
Michele Piccolini
@MichelePiccolini Los espacios en los nombres de archivo se pueden manejar con find -print0y xargs -0.
pasztorpisti
8

Suponiendo que desea replicar esta estructura de ./sourcea ./destination:

cd source
find . -name "*.csv" | xargs tar cvf - | (cd ../destination ; tar xfp -)

Estoy preparado para contar eso como una línea, el hecho de cd sourceser un caparazón incorporado.

MadHatter
fuente
2
No creo que realmente se refiera a un comando, simplemente no tener que marginar como en su ejemplo;)
tartiene la -Copción de evitar tener que cambiar primero el directorio.
Bart
8

Desde rsyncla página del manual:

-R, --relativo

Usa caminos relativos. Esto significa que los nombres de ruta completos especificados en la línea de comando se envían al servidor en lugar de solo las últimas partes de los nombres de archivo. Esto es particularmente útil cuando desea enviar varios directorios diferentes al mismo tiempo. Por ejemplo, si usó este comando:

rsync -av /foo/bar/baz.c remote:/tmp/

... esto crearía un archivo llamado baz.c en / tmp / en la máquina remota. Si en cambio usaste

rsync -avR /foo/bar/baz.c remote:/tmp/

entonces se crearía un archivo llamado /tmp/foo/bar/baz.c en la máquina remota, conservando su ruta completa. Estos elementos de ruta adicionales se denominan "directorios implícitos" (es decir, los directorios "foo" y "foo / bar" en el ejemplo anterior).

Entonces, esto también funcionaría:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
Geremia
fuente