我正在尝试编写一个简单的bash脚本,它将包含隐藏文件和文件夹的文件夹的全部内容复制到另一个文件夹中,但我想排除某些特定的文件夹。我怎么能做到这一点?
答案 0 :(得分:307)
使用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*
答案 1 :(得分:36)
将tar与管道一起使用。
cd /source_directory
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )
您甚至可以在ssh中使用此技术。
答案 2 :(得分:9)
您可以将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.
答案 3 :(得分:2)
类似于Jeff的想法(未经测试):
find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/
答案 4 :(得分:2)
你可以使用tar,使用--exclude选项,然后在目标中解压缩它。例如
cd /source_directory
tar cvf test.tar --exclude=dir_to_exclude *
mv test.tar /destination
cd /destination
tar xvf test.tar
请参阅tar的手册页以获取更多信息
答案 5 :(得分:0)
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
未经测试...
答案 6 :(得分:0)
受@ SteveLazaridis的回答启发,这将失败,这里是一个POSIX shell函数 - 只需复制并粘贴到你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"
答案 7 :(得分:0)
简单的解决方案(但我仍然更喜欢顶部评论中的 bash 模式匹配):
touch /path/to/target/.git
cp -n -ax * /path/to/target/
rm /path/to/target/.git
这利用了 -n
的 cp
选项,强制 cp
不覆盖现有目标。
缺点:适用于 GNU cp
。如果您没有 GNU cp
,那么 cp
操作可能会返回错误代码 (1
),这很烦人,因为您无法判断它是否是真正的失败.
答案 8 :(得分:-1)
运行:
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*
修改自:https://stackoverflow.com/a/2194500/749232
开始文件夹结构:
.
├── destination
└── source
├── fileToCopy.rtf
└── fileToExclude.rtf
运行:
rsync -av --exclude='fileToCopy.rtf' source/ destination
结尾文件夹结构:
.
├── destination
│ └── fileToExclude.rtf
└── source
├── fileToCopy.rtf
└── fileToExclude.rtf