¿Cómo puedo copiar archivos recursivamente por extensión de archivo, preservando la estructura del directorio?

71

En la línea de comandos de Linux, me gustaría copiar un conjunto (muy grande) de .txtarchivos de un directorio (y sus subdirectorios) a otro.

Necesito que la estructura del directorio permanezca intacta, y tengo que ignorar los archivos, excepto los que terminan en .txt.

equipaje no reclamado
fuente
2
Tener cp y buscar como etiquetas en su pregunta, ¿significa que está vinculado a estas opciones? Dado que su conjunto de datos es muy grande, tiene sentido suponer que el proceso de copia puede interrumpirse por algunos motivos y tendrá que reiniciarlo. No estoy seguro de que el enfoque find / cp pueda reanudar la transferencia y copiar solo la parte que falta. Si no está vinculado a find / cp, podría considerar rsync, que es más inteligente. Su opción --exclude le permitirá omitir archivos .txt.
vtest
Llamada justa - rsync probablemente es la mejor opción. No atado a encontrar / cp. (Los usé de todos modos, rsync no estaba instalado en la máquina remota, era un servidor web en vivo y quería dejar el menor espacio posible)
equipaje no reclamado

Respuestas:

96

Puedes usar find y cpio para hacer esto

cd /top/level/to/copy
find . -name '*.txt' | cpio -pdm /path/to/destdir

(-updm for overwrite destination content.)
cedric
fuente
porque m pensé que era solo para retener la fecha de modificación del archivo.
Mubashar
7
cd /source/path
find -type f -name \*.txt -exec install -D {} /dest/path/{} \;
sborsky
fuente
Te estás perdiendo un .después find. También en macOS 10.13.1, esto funcionó:find . -type f -name "*.txt" -exec install -v {} /dest/path/{} \;
sombrío
2

Otro enfoque

find . -name '*.txt' -exec rsync -R {} path/to/dext \;

Bagazo
fuente
Me gusta esta solución Solía find . -iname '*.txt' -exec rsync -Rptgon {} path/to/dext \;hacer una coincidencia entre mayúsculas y minúsculas y preservar la propiedad y los permisos.
MountainX
1

La forma más fácil que funcionó para mí:

cp --parents -R jobs/**/*.xml ./backup/

Una trampa es que tiene que navegar al directorio "deseado" antes para que la "ruta principal" sea correcta.

También asegúrate de haber habilitado los globos recursivos en bash:

shopt -s globstar
icyerasor
fuente
1

¿qué tal si primero lo copia con

cp -r /old/folder /new/folder

luego ve a la nueva carpeta y ejecuta

find . -type f ! -iname "*.txt" -delete

o solo

cp -r /old/folder /new/folder && find . -type f ! -iname "*.txt" -delete

Editar: ok, quieres un comando que filtre (¡no lo he probado porque mi sistema no tiene el cpiocomando!). Aquí es donde lo encontré: http://www.gnu.org/software/findutils/manual/html_mono/find.html#Copying-A-Subset-of-Files

find . -name "*.txt" -print0 |
     cpio -pmd0 /dest-dir

Por favor, probar primero esto, porque no he probado todavía. Si alguien verificara, eso sería genial.

Dennis
fuente
asiente Saludos: esto funcionaría, pero sin filtrar a .txt, estoy viendo algunos millones de archivos (que salen a unos pocos cientos de GB). Si es necesario, puede que tenga que hacerlo, pero me encantaría filtrar mientras se copia, si es posible
equipaje no reclamado
1
Saludos, versión editada funciona si elimino el '0' de -pmd0
unclaimedbaggage
Se debe mantener el 0en -pmd0y añadir -print0al final del findcomando (justo antes de la |).
G-Man
1

Intenté hacer lo mismo en macOS, pero ninguna de las opciones realmente funcionó para mí. Hasta que lo descubrí ditto.

Tuve que copiar muchos archivos .wav y hacer que omita los archivos de video ... Así que esto es lo que se me ocurrió:

find . -type f -iname "*.wav" -ls -exec ditto {} /destination/folder/{} \;

  • find .- Ejecuta buscar en la carpeta actual. asegúrese de hacerlo cd /source/folderantes de comenzar

  • -type f - Especifica solo buscar archivos

  • -iname "*.wav" - Esto le dice que busque mayúsculas y minúsculas * .wav
  • -ls- Esto le muestra el archivo en el que está trabajando. De lo contrario, no muestra nada.
  • -exec ditto {} /destination/folder/{} \; - Hace todo el trabajo de copiar y crear los archivos con el mismo árbol de directorios.
Benjamin McGuire
fuente
0

Navegue al directorio:

find . -regex '<regexp_to_get_directories_and_files_you_want>' | xargs -i cp -r --parents {} path/to/destination

Es un poco más directo y poderoso, si manejas expresiones regulares.

keywalker
fuente
-1

Navegue al directorio:

cp '*.css' /path/to/destination

Tendrá que navegar a cada carpeta en el directorio, pero esto es mejor que la mayoría de las opciones que he visto hasta ahora.

Fénix
fuente
Este método no es recursivo, lo que significa que para directorios grandes podría estar haciendo esto durante bastante tiempo ...
Iain Reid