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

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

9 ответов

Решение

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

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

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

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

Ты можешь использовать 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 выполняется только
       за вещи, к которым не было применено -прун. Поскольку
       условие `` и 'между тестами связывает более тесно, чем -o, это
       в любом случае по умолчанию, но скобки помогают показать, что происходит
       на.

Быстрый старт

Пробег:

rsync -av --exclude='path1/in/source' --exclude='path2/in/source' [source]/ [destination]

Заметки

  • -avr создаст новый каталог с именем [destination].
  • source а также source/ создавать разные результаты:
    • source- скопировать содержимое источника в место назначения.
    • source/- скопировать источник папки в место назначения.
  • Чтобы исключить много файлов:
    • --exclude-from=FILE - FILE - это имя файла, содержащего другие файлы или каталоги, которые нужно исключить.
  • --exclude также может содержать подстановочные знаки:
    • например --exclude=*/.svn*

Изменено с: /questions/11393909/rekursivno-kopirovat-papku-isklyuchaya-nekotoryie-papki/11393941#11393941


пример

Стартовая структура папок:

.
├── destination
└── source
    ├── fileToCopy.rtf
    └── fileToExclude.rtf

Пробег:

rsync -av --exclude='fileToCopy.rtf' source/ destination

Конечная структура папок:

.
├── destination
│   └── fileToExclude.rtf
└── source
    ├── fileToCopy.rtf
    └── fileToExclude.rtf

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

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

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

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

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

Простое решение (но я все же предпочел бы сопоставление с шаблоном bash из верхних комментариев):

      touch /path/to/target/.git
cp -n -ax * /path/to/target/
rm /path/to/target/.git

Это эксплуатирует -n опция, которая заставляет не перезаписывать существующие цели.

Недостаток: работает с GNU. Если у вас нет GNU, то cp операция может вернуть код ошибки ( 1), что раздражает, потому что тогда вы не сможете сказать, был ли это настоящий сбой.

Вдохновленный ответом @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"
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

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

Другие вопросы по тегам