¿Cómo usar el comando ‘cp’ para excluir un directorio específico?

Quiero copiar todos los archivos en un directorio, excepto algunos archivos en un subdirectorio específico. Me di cuenta de que el comando ‘cp‘ no tenía una opción –excluir. Entonces, ¿cómo puedo lograr esto?

rsync es rápido y fácil:

 rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude 

Puede usar --exclude múltiplos veces.

También puede agregar -n para ejecución en seco para ver qué se copiará antes de realizar una operación real, y si todo está bien, elimine -n de la línea de comandos.

Bueno, si la exclusión de ciertos patrones de nombre de archivo tenía que ser realizada por cada utilidad de archivo unix-ish (como cp, mv, rm, tar, rsync, scp, …), se produciría una inmensa duplicación de esfuerzo. En cambio, tales cosas se pueden hacer como parte de globbing , es decir, por su caparazón.

bash

Enlace al manual, busque extglob .

Ejemplo:

 $ shopt -s extglob
 $ echo images / *
 images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
 $ echo images /! (*. jpg)
 images / 004.bmp images / 2252.png

¡Así que pones un patrón dentro !() , Y niega la coincidencia. El patrón puede ser arbitrariamente complejo, comenzando con la enumeración de rutas individuales (como muestra Vanwaril en otra respuesta) !(filename1|path2|etc3) , para regex-cosas con estrellas y clases de caracteres. Consulte la página de manual para más detalles.

zsh

Enlace al manual, sección “generación de nombre de archivo” .

Puede hacer setopt KSH_GLOB y usar patrones tipo bash. O,

 % setopt EXTENDED_GLOB
 % echo images / *
 images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
 % echo images / * ~ * .jpg
 images / 004.bmp images / 2252.png

Entonces x~y coincide con el patrón x , pero excluye el patrón y . Una vez más, para obtener más información, consulte la página de manual.


pescado nuevo!

La concha de pescado tiene una respuesta mucho más bonita a esto:

 🐟 cp (cadena coincidente -v '* .excluded.names' - srcdir / *) destdir

Sugerencia de bonificación

Escriba cp * , presione Ctrl X * y solo vea lo que sucede. no es dañino, lo prometo

Por qué usar rsync cuando puedes hacer:

 find . -type f -not -iname '*/not-from-here/*' -exec cp '{}' '/dest/{}' ';' 

Esto supone que la estructura del directorio de destino es la misma que la de la fuente.

 cp -r `ls -A | grep -v "c"` $HOME/ 

La forma más fácil que encontré, donde puedes copiar todos los archivos que excluyen archivos y carpetas simplemente agregando sus nombres entre paréntesis:

 cp -r !(Filename1 | FoldernameX | Filename2) Dest/ 

Supongo que estás usando bash o dash. ¿Esto funcionaría?

 shopt -s extglob # sets extended pattern matching options in the bash shell cp $(ls -laR !(subdir/file1|file2|subdir2/file3)) destination 

Hacer un ls excluyendo los archivos que no desea, y usar eso como primer argumento para cp

Ampliando el comentario de mvds , esto funciona para mí

 cd dotfiles tar -c --exclude .git --exclude README . | tar -x -C ~/dotfiles2 

Otra opción más simple es instalar y usar rsync, que tiene una opción –exclude-dir, y se puede usar para archivos locales y remotos.

rsync

 rsync -r --verbose --exclude 'exclude_pattern' ./* /to/where/ 

y primero pruébelo con la opción -n para ver qué se va a copiar

Esta es una modificación de la respuesta de Linus Kleen. Su respuesta no funcionó para mí porque habría a. agregado al frente de la ruta del archivo que no le gusta a cp (la ruta se vería como source / .destination / file).

Este comando funcionó para mí:

find . -type f -not -path '*/exlude-path/*' -exec cp --parents '{}' '/destination/' \;

el comando –parents conserva la estructura del directorio.

 mv tobecopied/tobeexcluded . cp -r tobecopied dest/ mv tobeexcluded tobecopied/ 

Simplemente muévelo temporalmente a un directorio oculto (y renómbrelo después, si lo desea).

 mkdir .hiddendir cp * .hiddendir -R mv .hiddendir realdirname 

Es relativo al directorio de origen.
Esto excluirá la source/.git directorio source/.git de ser copiada.

 rsync -r --exclude '.git' source target 

Una forma sería usar find -0 con -prune para encontrar todos los archivos y directorios que desea mover, luego use xargs -0 para copiar cada uno.

 cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir 

Editar: se olvidó de excluir también la ruta de destino (de lo contrario, se copiaría recursivamente).

Utilizo un ciclo “do while” para leer la salida del comando find. En este ejemplo, estoy haciendo coincidir (en lugar de excluir) ciertos patrones, ya que hay un número de coincidencias de patrón más limitado que el que yo no quiero. Podría invertir la lógica con un -no delante de los indicadores -iname:

  find . -type f -iname "*.flac" -o -print0 -iname "*.mp3" -print0 -o -iname "*.wav" -print0 -o -iname "*.aac" -print0 -o -iname "*.wma" -print0 | while read -d $'\0' file; do cp -ruv "$file" "/media/wd/network_sync/music/$file"; done 

Utilizo lo anterior para copiar todos los archivos de tipo de música que son más nuevos en mi servidor que los archivos en un Western Digital TV Live Hub que he montado en / media / wd. Uso lo anterior porque tengo muchos archivos de DVD, mpegs, etc. que quiero excluir Y porque por alguna razón parece que rsync está copiando, pero después de mirar el dispositivo wd, los archivos no están allí a pesar de que no errores durante la rsync con este comando:

  rsync -av --progress --exclude=*.VOB --exclude=*.avi --exclude=*.mkv --exclude=*.ts --exclude=*.mpg --exclude=*.iso --exclude=*ar --exclude=*.vob --exclude=*.BUP --exclude=*.cdi --exclude=*.ISO --exclude=*.shn --exclude=*.MPG --exclude=*.AVI --exclude=*.DAT --exclude=*.img --exclude=*.nrg --exclude=*.cdr --exclude=*.bin --exclude=*.MOV --exclude=*.goutputs* --exclude=*.flv --exclude=*.mov --exclude=*.m2ts --exclude=*.cdg --exclude=*.IFO --exclude=*.asf --exclude=*.ite /media/2TB\ Data/data/music/* /media/wd/network_sync/music/ 

rsync es realmente bastante complicado. tiene que hacer múltiples pruebas para que funcione.

Digamos que quiere copiar /var/www/html a /var/www/dev pero necesita excluir /var/www/html/site/video/ directory debido a su tamaño. El comando sería:

rsync -av --exclude 'sites/video' /var/www/html/ /var/www/dev

Alguna advertencia :

  1. Se necesita la última barra / en la fuente, de lo contrario también copiará el directorio de origen en lugar de su contenido y se convertirá en /var/www/dev/html/xxxx , que tal vez no sea lo que usted desea.
  2. La ruta --exclude es relativa a la fuente directamente. Incluso si pones una ruta absoluta completa, no funcionará.

  3. -v es verboso, -a es para el modo de archivo, lo que significa que desea recursividad y desea conservar casi todo.