Скопировать папку рекурсивно, исключая некоторые папки
Я пытаюсь написать простой bash script, который скопирует все содержимое папки, включая скрытые файлы и папки, в другую папку, но я хочу исключить определенные определенные папки. Как я мог достичь этого?
Ответы
Ответ 1
Использовать 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*
Ответ 2
Используйте tar вместе с трубой.
cd /source_directory
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )
Вы даже можете использовать эту технику через ssh.
Ответ 3
Вы можете использовать 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.
Ответ 4
Подобно идее Джеффа (непроверенный):
find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/
Ответ 5
вы можете использовать tar, с параметром --exclude, а затем развернуть его в пункте назначения. например,
cd /source_directory
tar cvf test.tar --exclude=dir_to_exclude *
mv test.tar /destination
cd /destination
tar xvf test.tar
см. справочную страницу tar для дополнительной информации
Ответ 6
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
Непроверено...
Ответ 7
вызванный ответом @SteveLazaridis, который потерпит неудачу, вот функция оболочки POSIX - просто скопируйте и вставьте в файл с именем cpx
в yout $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 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"