web-dev-qa-db-fra.com

Copier le dossier de manière récursive, à l'exclusion de certains dossiers

J'essaie d'écrire un script bash simple qui va copier tout le contenu d'un dossier, y compris les fichiers et dossiers cachés, dans un autre dossier, mais je veux exclure certains dossiers spécifiques. Comment pourrais-je y parvenir?

180
trobrock

Utilisez rsync:

rsync -av --exclude='path1/to/exclude' --exclude='path2/to/exclude' source destination

Notez que l'utilisation de source et source/ est différente. Un slash de fin signifie copier le contenu du dossier source dans destination. Sans la barre oblique finale, cela signifie que vous copiez le dossier source dans destination.

Si vous devez exclure de nombreux répertoires (ou fichiers), vous pouvez également utiliser --exclude-from=FILE, où FILE est le nom d'un fichier contenant des fichiers ou des répertoires à exclure.

--exclude peut également contenir des caractères génériques, tels que --exclude=*/.svn*

302
Kaleb Pederson

Utilisez du goudron avec un tuyau.

cd /source_directory
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )

Vous pouvez même utiliser cette technique sur ssh.

36
Kyle Butt

Vous pouvez utiliser find avec l'option -Prune.

Un exemple de man find:

 cd /source-dir
 trouver . -name .snapshot -Prune -o\(\! -name * ~ -print0 \) | 
 cpio -pmd0 /dest-dir

 Cette commande copie le contenu de/source-dir dans/dest-dir, mais omet 
 fichiers et répertoires nommés .snapshot (et tout ce qu’ils contiennent). Ça aussi
 omet les fichiers ou les répertoires dont le nom se termine par ~, mais pas leur con ‐
 des tentes. La construction -Prune -o\(... -print0 \) est assez courante. Le
 L'idée ici est que l'expression avant -Prune correspond aux choses qui sont 
 être élagué. Cependant, l'action -Prune elle-même retourne la valeur true, donc le 
 En suivant -o, on s'assure que le côté droit est évalué uniquement pour 
 les répertoires qui n'ont pas été élagués (le contenu des répertoires élagués 
 n'est pas même visité, leur contenu est donc sans importance) .
 L'expression à droite du -o est entre parenthèses seulement 
 pour plus de clarté. Il souligne que l'action -print0 n'a lieu que 
 pour les choses qui n'ont pas -Prune appliqué à eux. Parce que le
 La condition par défaut `et 'entre les tests lie plus étroitement que -o, this 
 est la valeur par défaut quand même, mais les parenthèses aident à montrer ce qui se passe 
 sur.
9
Dennis Williamson

Semblable à l'idée de Jeff (non testé):

find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/
2
Matthew Flaschen

vous pouvez utiliser tar avec l'option --exclude, puis le décompresser dans la destination. par exemple

cd /source_directory
tar cvf test.tar --exclude=dir_to_exclude *
mv test.tar /destination 
cd /destination  
tar xvf test.tar

voir la page de manuel de tar pour plus d'informations

2
ghostdog74
EXCLUDE="foo bar blah jah"                                                                             
DEST=$1

for i in *
do
    for x in $EXCLUDE
    do  
        if [ $x != $i ]; then
            cp -a $i $DEST
        fi  
    done
done

Non testé ...

0
Steve Lazaridis

inspiré par la réponse de @ SteveLazaridis, qui échouerait, voici une fonction POSIX Shell - il suffit de copier et coller dans un fichier nommé cpx in yout $PATH et de le rendre exécutable (chmod a+x cpr). [La source est maintenant conservée dans mon GitLab .

#!/bin/sh

# usage: cpx [-n|--dry-run] "from_path" "to_path" "newline_separated_exclude_list"
# limitations: only excludes from "from_path", not it's subdirectories

cpx() {
# run in subshell to avoid collisions
  (_CopyWithExclude "$@")
}

_CopyWithExclude() {
  case "$1" in
    -n|--dry-run) { DryRun='echo'; shift; } ;;
  esac

  from="$1"
  to="$2"
  exclude="$3"

  $DryRun mkdir -p "$to"

  if [ -z "$exclude" ]; then
      cp "$from" "$to"
      return
  fi

  ls -A1 "$from" \
    | while IFS= read -r f; do
        unset excluded
        if [ -n "$exclude" ]; then
          for x in $(printf "$exclude"); do
          if [ "$f" = "$x" ]; then
              excluded=1
              break
          fi
          done
        fi
        f="${f#$from/}"
        if [ -z "$excluded" ]; then
          $DryRun cp -R "$f" "$to"
        else
          [ -n "$DryRun" ] && echo "skip '$f'"
        fi
      done
}

# Do not execute if being sourced
[ "${0#*cpx}" != "$0" ] && cpx "$@"

Exemple d'utilisation

EXCLUDE="
.git
my_secret_stuff
"
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE"
0
go2null