it-swarm.com.ru

Рекурсивно копировать папку, исключая некоторые папки

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

180
trobrock

Используйте 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*

302
Kaleb Pederson

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

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

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

36
Kyle Butt

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

Пример из man find:

 cd /source-dir
 находить . -name .snapshot -Prune -o\(\! -name * ~ -print0 \) | 
 cpio -pmd0 /dest-dir

 Эта команда копирует содержимое/source-dir в/dest-dir, но пропускает 
 файлы и каталоги с именем .snapshot (и все, что в них). Это также
 пропускает файлы или каталоги, чье имя оканчивается на ~, но не их содержимое. палатки. Конструкция -Prune -o\(... -print0 \) довольно распространена. 
 Идея в том, что выражение перед -Prune соответствует вещам 
 быть обрезанным. Однако само действие -Prune возвращает true, поэтому 
 следующий -o гарантирует, что правая часть вычисляется только для 
 те каталоги, которые не были удалены (содержимое сокращенных каталогов 
 даже не посещается, поэтому их содержимое не имеет значения) .
 Выражение справа от -o только в скобках 
 для ясности. Подчеркивается, что действие -print0 выполняется только 
 за то, что не имело -Прун применяется к ним. Поскольку
 условие `and 'между тестами связывает более тесно, чем -o, это 
 в любом случае это значение по умолчанию, но скобки помогают показать, что происходит 
 на.
9
Dennis Williamson

Похоже на идею Джеффа (не проверено):

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

вы можете использовать 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
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

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

0
Steve Lazaridis

вдохновленный ответом @ 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 "[email protected]")
}

_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 "[email protected]"

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

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