Comment utiliser la commande 'cp' pour exclure un répertoire spécifique?

411

Je souhaite copier tous les fichiers d'un répertoire, à l'exception de certains fichiers d'un sous-répertoire spécifique. J'ai remarqué que la commande 'cp' n'avait pas d'option --exclude. Alors, comment puis-je y parvenir?

David Liu
la source
18
rsync?
ajreal
6
tar -c | tar -x?
mvds
1
@mvds, d'accord avec vous, utiliser tar avec '--exclude' est une bonne idée.
Huang F. Lei
2
Copie
phuclv

Réponses:

704

rsync est rapide et facile:

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

Vous pouvez utiliser --excludeplusieurs fois.

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

Notez que l' option dir thefoldertoexcludeaprès --excludeest relative à sourcefolder, c'est-à-dire sourcefolder/thefoldertoexclude.

Vous pouvez également ajouter -npour un essai à sec pour voir ce qui sera copié avant d'effectuer une opération réelle, et si tout va bien, supprimez -nde la ligne de commande.

écheveau
la source
3
D'accord, vous ne pouvez pas battre la simplicité et la puissance de--exclude
Matthew Wilcoxson
31
est le thefoldertoexcluderelatif au sourcefolderou le répertoire de travail actuel? merci
Beebee
46
C'est relatif au dossier source. Cela exclura la copie du dossier source / .git. rsync -r --exclude '.git' source target
orkoden
15
Peut-être que je me trompe, mais je pense que c'est une bonne pratique d'ajouter des "commutateurs" avant "paramètres". La page de manuel de rsync rapporte également --exclude utilisable comme avec la syntaxe "=" ou sans. Donc, pour standardiser les systèmes d'exploitation, j'utiliserais rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder- de toute façon un vote positif pour le rsync au lieu de la recherche, car vous pouvez facilement utiliser des chemins absolus pour la source tandis que dans la recherche, c'est plus difficile car il utilise le {}dans le dst.
Xavi Montero, le
1
@mamun Bien sûr, par exemple, du serveur distant à la machine locale: $ rsync [email protected]:/var/www/mypage /var/www/mylocalpage/ou du local à distant$ rsync /var/www/mylocalpage/ [email protected]:/var/www/mypage
sobi3ch
84

Eh bien, si l'exclusion de certains modèles de nom de fichier devait être effectuée par chaque utilitaire de fichier unix-ish (comme cp, mv, rm, tar, rsync, scp, ...), une immense duplication des efforts se produirait. Au lieu de cela, ces choses peuvent être effectuées dans le cadre de la globalisation , c'est-à-dire par votre shell.

frapper

man 1 bash, / extglob .

Exemple:

$ 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

Donc, vous venez de mettre un motif à l'intérieur !(), et cela annule la correspondance. Le modèle peut être arbitrairement complexe, à partir de l'énumération des chemins individuels (comme Vanwaril le montre dans une autre réponse):, !(filename1|path2|etc3)à des choses semblables à des regex avec des étoiles et des classes de caractères. Reportez-vous à la page de manuel pour plus de détails.

zsh

man 1 zshexpn, / génération de nom de fichier .

Vous pouvez faire setopt KSH_GLOBet utiliser des modèles de type bash. Ou,

% setopt EXTENDED_GLOB
% images d'écho / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
% écho images / * ~ * .jpg
images / 004.bmp images / 2252.png

Correspond donc au x~ymodèle x, mais exclut le modèle y. Encore une fois, pour plus de détails, reportez-vous à la page de manuel.


poisson nouveau!

La coquille de poisson a une réponse beaucoup plus jolie à cela:

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

Bonus pro-tip

Tapez cp *, appuyez CtrlX*et voyez ce qui se passe. ce n'est pas nocif je le promets

ulidtko
la source
@MikhailGolubtsov peut-être parce que la globalisation n'est pas récursive et fonctionne un niveau à la fois. Modifié. PS: ça marche zshquand même.
ulidtko
3
Nice pro-tip! De cette façon, vous pouvez facilement supprimer des éléments uniques. Merci beaucoup!
taffit
BTW, pour désactiver les fonctionnalités étendues de correspondance de motifs dans Bash, exécutez setopt -u extglob.
Rockallite
49

Pourquoi utiliser rsyncquand vous pouvez le faire:

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

Cela suppose que la structure du répertoire cible est la même que celle de la source.

Linus Kleen
la source
8
Je pense que vous avez besoin de l' -pathargument pour tester les hiérarchies de chemins, pas
James Murty
3
Et vous aurez également besoin d'un point-virgule à la fin:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Matthew Wilcoxson
1
Wow, ça ne me laissera pas: "Les modifications doivent être composées d'au moins 6 caractères"!
Matthew Wilcoxson
1
@MatthewWilcoxson Meh. Ces restrictions seront levées dès que vous gagnerez un peu plus de rep. J'ai modifié la réponse en conséquence. Merci encore!
Linus Kleen
1
@Henning pourquoi pas rsync? Parce qu'il peut ne pas être présent dans le système! tandis que find, cpest toujours à leur place. Ou vous, du genre de gars, qui avez installé 2 concerts pour faire des choses simples?
Reishin
37
cp -r `ls -A | grep -v "c"` $HOME/
vigne kumar
la source
1
A travaillé pour moi dans Windows 10 .sh
atwellpub
Création d'une fonction shell qui simplifie l'utilisation du chemin source personnalisé et l'exclusion d'un seul fichier ou répertoire: # $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
échoue avec les répertoires avec des espaces
Sérgio
27

Le moyen le plus simple que j'ai trouvé, où vous pouvez copier tous les fichiers à l'exception des fichiers et des dossiers simplement en ajoutant leurs noms entre parenthèses:

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/
courbe de sécurité
la source
9
Ça ne marche pas pour moi. Je reçois-bash: !: event not found
Genorama
8
shopt -s extglob (exécutez ceci pour activer! dans cp, rm et autres)
imkost
13

Développer le commentaire de mvds , cela fonctionne pour moi

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

C'est relatif au répertoire source.
Cela exclura le répertoire source/.gitd'être copié.

rsync -r --exclude '.git' source target
Niyaz Ahmed Qureshi
la source
Quelle est la différence / amélioration par rapport à la première réponse?
réduction de l'activité le
8

rsync

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

et essayez d'abord avec l'option -n pour voir ce qui va être copié

dzon
la source
Quelle est la différence / amélioration par rapport à la première réponse?
réduction de l'activité le
7

Je suppose que vous utilisez bash ou dash. Est-ce que cela fonctionnerait?

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

Faire un ls en excluant les fichiers dont vous ne voulez pas, et l'utiliser comme premier argument pour cp

Vanwaril
la source
9
Vous pouvez sauter le supplément lset simplement le faire cp !(file1|file1) dest.
Shawn Chin
N'utilisez pas -laR. il ajoute une chaîne qui interfère avec cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL
5

Une autre option plus simple consiste à installer et à utiliser rsync qui a une option --exclude-dir, et peut être utilisé pour les fichiers locaux et distants.

ehudokai
la source
4

rsyncest en fait assez délicat. avoir à faire plusieurs tests pour le faire fonctionner.

Supposons que vous souhaitiez copier /var/www/htmldans, /var/www/devmais que vous deviez exclure le /var/www/html/site/video/ répertoire, peut-être en raison de sa taille. La commande serait:

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

Quelques mises en garde :

  1. La dernière barre oblique /dans la source est nécessaire, sinon elle copiera également le répertoire source plutôt que son contenu et deviendra /var/www/dev/html/xxxx, ce qui n'est peut-être pas ce que vous voulez.
  2. Le --excludechemin est relatif à la source directement. Même si vous mettez le chemin absolu complet, cela ne fonctionnera pas.

  3. -vest pour verbeux, -aest pour le mode archive, ce qui signifie que vous voulez la récursivité et que vous souhaitez conserver presque tout.

LeOn - Han Li
la source
une solution simple qui prend soin des caractères spéciaux et des espaces blancs
Sérgio
Merci d'expliquer les paramètres, contrairement à la première réponse actuelle!
réduction de l'activité le
3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

Edit: oublié d'exclure également le chemin cible (sinon il serait récursivement copié).

travail sudo
la source
4
attention aux entrées de répertoire contenant des espaces.
Paulo Scardine
3

Il s'agit d'une modification de la réponse de Linus Kleen. Sa réponse n'a pas fonctionné pour moi car il y en aurait un. ajouté devant le chemin du fichier que cp n'aime pas (le chemin ressemblerait à source / .destination / file).

Cette commande a fonctionné pour moi:

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

la commande --parents conserve la structure du répertoire.

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

Déplacez-le simplement temporairement dans un répertoire caché (et renommez-le après, si vous le souhaitez).

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname
lama12345
la source
1
Pas assez peut-être - mais c'est la seule option que j'ai trouvée ici qui fonctionne avec cpun shell POSIX standard comme sh.
tomekwi
1
Cette réponse est considérablement sous-estimée. C'est la réponse la plus compatible, la plus facile à lire et à comprendre. Bravo, je ne sais pas pourquoi je n'y ai pas pensé.
Robert Talada
Merci @RobertTalada, jusqu'où ira la réponse à partir de maintenant? ️‍🌈
lama12345
0

J'utilise une boucle "do while" pour lire la sortie de la commande find. Dans cet exemple, je fais correspondre (plutôt que d'exclure) certains modèles car il y a un nombre plus limité de correspondances de modèles que je veux que je ne veux pas. Vous pouvez inverser la logique avec un -not devant les drapeaux -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

J'utilise ce qui précède pour copier tous les fichiers de type de musique qui sont plus récents sur mon serveur que les fichiers sur un Western Digital TV Live Hub que j'ai monté dans / media / wd. J'utilise ce qui précède parce que j'ai beaucoup de fichiers DVD, mpeg, etc. que je veux exclure ET parce que pour une raison quelconque, rsync semble copier, mais après avoir regardé le périphérique wd, les fichiers ne sont pas là malgré aucun erreurs lors de la rsync avec cette commande:

    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/
user3610268
la source
0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

La première partie lstous les fichiers mais les fichiers spécifiques cachés avec indicateur -I. La sortie de lsest utilisée comme entrée standard pour la deuxième partie. xargsconstruire et exécuter la commande à cp -rf -t destdirpartir de l'entrée standard. l'indicateur -rsignifie copier les répertoires de manière récursive, -fsignifie copier les fichiers de force qui écraseront les fichiers dans le destdir, -tspécifiez la copie du répertoire de destination vers.

LouisXW
la source
0

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

Shashwot Risal
la source