Рекурсивно копировать папку, исключая некоторые папки - PullRequest
185 голосов
/ 03 февраля 2010

Я пытаюсь написать простой bash-скрипт, который будет копировать все содержимое папки, включая скрытые файлы и папки, в другую папку, но я хочу исключить некоторые конкретные папки. Как мне этого добиться?

Ответы [ 7 ]

309 голосов
/ 03 февраля 2010

Использовать rsync:

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

Обратите внимание, что использование source и source/ отличается. Конечная косая черта означает копирование содержимого папки source в destination. Без косой черты это означает, что папка source скопирована в destination.

В качестве альтернативы, если у вас есть много каталогов (или файлов) для исключения, вы можете использовать --exclude-from=FILE, где FILE - это имя файла, содержащего файлы или каталоги для исключения.

--exclude также может содержать символы подстановки, такие как --exclude=*/.svn*

37 голосов
/ 03 февраля 2010

Используйте смолу вместе с трубкой.

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

Вы можете даже использовать эту технику в ssh.

9 голосов
/ 03 февраля 2010

Вы можете использовать find с опцией -prune.

Пример из man find:

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

       This command copies the contents of /source-dir to /dest-dir, but omits
       files  and directories named .snapshot (and anything in them).  It also
       omits files or directories whose name ends in ~,  but  not  their  con‐
       tents.  The construct -prune -o \( ... -print0 \) is quite common.  The
       idea here is that the expression before -prune matches things which are
       to  be  pruned.  However, the -prune action itself returns true, so the
       following -o ensures that the right hand side  is  evaluated  only  for
       those  directories  which didn't get pruned (the contents of the pruned
       directories are not even visited, so their  contents  are  irrelevant).
       The  expression on the right hand side of the -o is in parentheses only
       for clarity.  It emphasises that the -print0 action  takes  place  only
       for  things  that  didn't  have  -prune  applied  to them.  Because the
       default `and' condition between tests binds more tightly than -o,  this
       is  the  default anyway, but the parentheses help to show what is going
       on.
2 голосов
/ 03 февраля 2010

вы можете использовать tar с параметром --exclude, а затем распаковать его в месте назначения. например,

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

см. Справочную страницу tar для получения дополнительной информации

2 голосов
/ 03 февраля 2010

Аналогично идее Джеффа (не проверено):

find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/
0 голосов
/ 26 октября 2017

Вдохновленный ответом @ SteveLazaridis, который потерпит неудачу, вот функция оболочки POSIX - просто скопируйте и вставьте файл с именем cpx в $PATH и сделайте его исполняемым (chmod a+x cpr). [Источник теперь поддерживается в моем 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 "$@"

Пример использования

EXCLUDE="
.git
my_secret_stuff
"
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE"
0 голосов
/ 03 февраля 2010
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

Не проверено ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...