Рекурсивно копировать папку, исключая некоторые папки
Я пытаюсь написать простой сценарий 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
Непроверенные...