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

411

Quiero copiar todos los archivos en un directorio excepto algunos archivos en un subdirectorio específico. He notado que el comando 'cp' no tenía una opción --exclude. Entonces, ¿cómo puedo lograr esto?

David Liu
fuente
18
rsync?
ajreal
66
tar -c | tar -x?
mvds
1
@mvds, de acuerdo con usted, usar tar con '--exclude' es una buena idea.
Huang F. Lei

Respuestas:

704

rsync es rápido y fácil:

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

Puedes usar --excludemúltiples veces.

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

Tenga en cuenta que el directorio thefoldertoexcludedespués de --excludela opción es relativa a la sourcefolder, es decir, sourcefolder/thefoldertoexclude.

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

madeja
fuente
3
De acuerdo, no se puede superar la simplicidad y el poder de--exclude
Mateo Wilcoxson
31
thefoldertoexcludeCuál es el relativo al sourcefolderdirectorio de trabajo actual? gracias
Beebee
46
Es relativo a la carpeta de origen. Esto excluirá la carpeta fuente / .git de ser copiada. rsync -r
--excluye el
15
Tal vez me equivoque, pero creo que es una buena práctica agregar "interruptores" antes de "parámetros". También la página del manual de informes rsync --excluye utilizable como con la sintaxis "=" o sin ella. Por lo tanto, para estandarizar en todos los sistemas operativos, usaría rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder, de todos modos, votar a favor de rsync en lugar de find, ya que puede usar fácilmente rutas absolutas para la fuente mientras que en find es más complicado ya que usa {}en dst.
Xavi Montero
1
@mamun Por supuesto, por ejemplo, del servidor remoto a la máquina local: $ rsync [email protected]:/var/www/mypage /var/www/mylocalpage/o de local a remoto$ rsync /var/www/mylocalpage/ [email protected]:/var/www/mypage
sobi3ch
84

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

golpetazo

man 1 bash, / 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 solo pones un patrón dentro !()y niega el partido. El patrón puede ser arbitrariamente complejo, comenzando por la enumeración de rutas individuales (como lo muestra Vanwaril en otra respuesta): !(filename1|path2|etc3)a cosas similares a expresiones regulares con estrellas y clases de personajes. Consulte la página de manual para más detalles.

zsh

man 1 zshexpn, / generación de nombre de archivo .

Puedes hacer setopt KSH_GLOBy usar patrones tipo bash. O,

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

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


pez nuevo!

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

🐟 cp (string match -v '* .excluded.names' - srcdir / *) destdir

Bonificación pro-tip

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

ulidtko
fuente
@MikhailGolubtsov quizás sea porque el globbing no es recursivo y funciona un nivel a la vez. Editado PD: zshaunque funciona.
ulidtko
3
Buen consejo profesional! De esta manera, puede eliminar elementos individuales fácilmente. ¡Muchas gracias!
taffit
Por cierto, para desactivar las características de coincidencia de patrones extendidos en Bash, ejecute setopt -u extglob.
Rockallite
49

¿Por qué usar rsynccuando 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 del origen.

Linus Kleen
fuente
8
Creo que necesita el -pathargumento para probar las jerarquías de ruta, no -iname
James Murty
3
Y también necesitará un punto y coma al final:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Matthew Wilcoxson
1
Wow, no me deja: "Las ediciones deben tener al menos 6 caracteres".
Matthew Wilcoxson
1
@MatthewWilcoxson Meh. Esas restricciones se levantarán tan pronto como ganes un poco más de reputación. Edité la respuesta en consecuencia. ¡Gracias de nuevo!
Linus Kleen
1
@Henning ¿por qué no rsync? ¡Porque puede no estar presente en el sistema! mientras find, cpsiempre está en sus lugares. ¿O eres de gente que instaló 2 gigas de cosas para hacer cosas simples?
Reishin
37
cp -r `ls -A | grep -v "c"` $HOME/
Vineet Kumar
fuente
1
Me funcionó en Windows 10 .sh
atwellpub
Hizo una función de shell que simplifica el uso de la ruta de origen personalizada y la exclusión de un solo archivo o directorio: # $1 = source path # $2 = destination path # $3 = filter copy_from_source_to_destination_except_filter() { cp -r $(ls -A $1 | grep -v -w $3 | awk -v path=$1 '{printf "%s/%s ", path, $1}') $2 }
ElectRocnic
falla con directorios con espacios
Sérgio
27

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

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/
curva segura
fuente
99
No funciona para mi Me sale-bash: !: event not found
geneorama
8
shopt -s extglob (ejecute esto para habilitar! en cp, rm y otros)
imkost
13

Ampliando el comentario de mvds , esto funciona para mí

cd dotfiles
tar -c --exclude .git --exclude README . | tar -x -C ~/dotfiles2
Steven Penny
fuente
10

Es relativo al directorio fuente.
Esto excluirá el directorio source/.gitde ser copiado.

rsync -r --exclude '.git' source target
Niyaz Ahmed Qureshi
fuente
¿Cuál es la diferencia / mejora en comparación con la respuesta principal?
reducción de actividad el
8

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

dzon
fuente
¿Cuál es la diferencia / mejora en comparación con la respuesta principal?
reducción de actividad el
7

Supongo que estás usando bash o dash. ¿Funcionaría esto?

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 el primer argumento para cp

Vanwaril
fuente
99
Puede omitir el extra lsy simplemente hacerlo cp !(file1|file1) dest.
Shawn Chin
No use -laR. agrega cadenas que interfieren con cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL
5

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

ehudokai
fuente
4

rsyncEn realidad es bastante complicado. tiene que hacer múltiples pruebas para que funcione.

Digamos que usted quiere copiar /var/www/htmla /var/www/dev, pero necesidad de excluir /var/www/html/site/video/ directorio tal vez debido a su tamaño. El comando sería:

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

Algunas advertencias :

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

  3. -ves detallado, -aes para el modo de archivo, lo que significa que desea recurrencia y desea preservar casi todo.

LeOn - Han Li
fuente
una solución simple que cuida los caracteres especiales y los espacios en blanco
Sérgio
¡Gracias por explicar los parámetros, a diferencia de la respuesta principal actual!
reducción de actividad el
3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

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

trabajo de sudo
fuente
44
cuidado con las entradas de directorio que contienen espacios.
Paulo Scardine
3

Esta es una modificación de la respuesta de Linus Kleen. Su respuesta no funcionó para mí porque habría un. agregado delante de la ruta del archivo que a cp no le gusta (la ruta se vería como fuente / .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.

Milan Simek
fuente
2
mv tobecopied/tobeexcluded .
cp -r tobecopied dest/
mv tobeexcluded tobecopied/
John Smith
fuente
2

Simplemente muévalo temporalmente a un directorio oculto (y cámbiele el nombre después, si lo desea).

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname
lama12345
fuente
1
Tal vez no sea bonito, pero esta es la única opción que he encontrado aquí que funciona con cpun shell POSIX estándar como sh.
tomekwi
1
Esta respuesta está dramáticamente subestimada. Esta es la respuesta más compatible, fácil de leer y fácil de entender. Felicitaciones, no sé por qué no pensé en eso.
Robert Talada
Gracias @RobertTalada, ¿hasta dónde llegará la respuesta a partir de ahora? ️‍🌈
lama12345
0

Utilizo un bucle "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 más limitado de coincidencias de patrones que quiero que no quiero. Puede revertir la lógica con un -no delante de las banderas -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. Utilizo lo anterior porque tengo muchos archivos DVD, mpegs, etc. que quiero excluir Y porque por alguna razón parece que rsync se está copiando, pero después de mirar el dispositivo wd, los archivos no están ahí a pesar de que no errores durante el 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/
usuario3610268
fuente
0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

La primera parte lstodos los archivos pero archivos específicos ocultos con bandera -I. La salida de lsse utiliza como entrada estándar para la segunda parte. xargsconstruir y ejecutar comandos cp -rf -t destdirdesde la entrada estándar. la bandera-r significa copiar directorios de forma recursiva, -fsignifica copiar archivos a la fuerza que sobrescribirán los archivos en destdir, -tespecifique la copia del directorio de destino.

LouisXW
fuente
0

cp -r ls -A | grep -v "Excluded_File_or_folder"../$target_location -v

Shashwot Risal
fuente