546 votes

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

Je veux copier tous les fichiers d'un répertoire sauf certains fichiers d'un sous-répertoire spécifique. J'ai remarqué que cp La commande n'a pas eu le --exclude option. Alors, comment puis-je y parvenir ?

23 votes

8 votes

tar -c | tar -x ?

1 votes

@mvds, je suis d'accord avec vous, utiliser tar avec '--exclude' est une bonne idée.

917voto

hank Points 762

rsync est rapide et facile :

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

Vous pouvez utiliser --exclude plusieurs fois.

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

Notez que le dir thefoldertoexclude après --exclude est relative à l'option sourcefolder c'est-à-dire, sourcefolder/thefoldertoexclude .

Vous pouvez également ajouter -n pour faire un essai afin de voir ce qui sera copié avant d'effectuer l'opération réelle, et si tout est ok, supprimez -n à partir de la ligne de commande.

3 votes

Je suis d'accord, vous ne pouvez pas battre la simplicité et la puissance de --exclude

37 votes

Est le thefoldertoexclude par rapport à la sourcefolder ou le répertoire de travail actuel ?

50 votes

Il est relatif au dossier source. Ceci exclura le dossier source/.git de la copie. rsync -r --exclude '.git' source cible

108voto

ulidtko Points 3834

Eh bien, si l'exclusion de certains modèles de noms de fichiers devait être effectuée par tous les utilitaires de fichiers unixiens (comme cp, mv, rm, tar, rsync, scp, ...), il y aurait une immense duplication des efforts. Au lieu de cela, de telles choses peuvent être faites dans le cadre de globbing c'est-à-dire par votre coquille.

bash

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

Donc tu mets juste un modèle à l'intérieur !() et cela annule la correspondance. Le motif peut être arbitrairement complexe, à partir d'une énumération de chemins individuels (comme le montre Vanwaril dans une autre réponse) : !(filename1|path2|etc3) à des choses de type 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 noms de fichiers .

Vous pouvez faire setopt KSH_GLOB et utiliser des motifs de type bash. Ou bien,

% 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

Alors x~y correspond au modèle x mais exclut le modèle y . Une fois encore, pour plus de détails, reportez-vous à la page de manuel.


poisson nouveau !

El poisson La coquille a un réponse beaucoup plus jolie à ça :

1 votes

@MikhailGolubtsov peut-être que c'est parce que le globbing n'est pas récursif et fonctionne un niveau à la fois. Modifié. P.S : cela fonctionne dans zsh cependant.

7 votes

Bon conseil ! De cette façon, vous pouvez supprimer facilement les éléments individuels. Merci beaucoup !

0 votes

En outre, pour désactiver les fonctions étendues de recherche de motifs dans Bash, exécutez la commande suivante setopt -u extglob .

58voto

Linus Kleen Points 15925

Pourquoi utiliser rsync quand vous pouvez le faire :

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

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

9 votes

Je pense que vous avez besoin de la -path pour tester les hiérarchies de chemins, et non -iname

5 votes

Et vous aurez aussi besoin d'un point-virgule à la fin : find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;

0 votes

@MatthewWilcoxson Merci Matthew, allez-y et modifiez ma réponse.

44voto

vineet kumar Points 89
cp -r `ls -A | grep -v "c"` $HOME/

1 votes

Cela a fonctionné pour moi sous Windows 10 .sh

0 votes

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 }

1 votes

Échoue avec les répertoires contenant des espaces

7voto

Vanwaril Points 2263

Je suppose que vous utilisez bash ou dash. Cela fonctionnerait-il ?

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

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

9 votes

Vous pouvez sauter le supplément ls et faire simplement cp !(file1|file1) dest .

0 votes

N'utilisez pas -laR. Il ajoute des chaînes qui interfèrent avec cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X