我想编写一个简单的bash脚本,将一个文件夹中包括隐藏文件和文件夹在内的所有内容复制到另一个文件夹中,但我想排除某些特定的文件夹。如何实现这一目标?
使用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*
rsync -av --exclude='.git/' ../old-repo/ .
- nycynik使用tar命令和管道一起使用。
cd /source_directory
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )
你甚至可以在 ssh 上使用这种技术。
rsync
可用且你不想费心安装它时,这很完美。 - Dániel Kis-Nagyrsync
went unavailable for us. So i updated the above tar a bit and this is what i came up with. tar -cf - --exclude='./folder' --exclude='./file.tar' ./source_directory | tar -xf - -C ./destination_directory
- Panduka-prune
选项的 find
命令。man find
的示例:
cd /source-dir find . -name .snapshot -prune -o \( \! -name *~ -print0 \)| cpio -pmd0 /dest-dir 这条命令将 /source-dir 目录中的内容复制到 /dest-dir 中,但省略了名为 .snapshot 的文件和目录(以及其中的所有内容)。它还省略了名称以 ~ 结尾的文件或目录,但不包括其内容。-prune -o \( ... -print0 \) 结构非常常见。这里的想法是,在 -prune 之前的表达式匹配要被修剪的内容。然而,-prune 动作本身返回真值,因此以下的 -o 确保右侧只对未被修剪的目录进行评估(已修剪的目录的内容甚至不会被访问,所以它们的内容是不相关的)。在 -o 右侧的表达式只是为了清晰起见加上的括号。它强调了 -print0 操作仅适用于没有应用 -prune 的事物。由于测试之间的默认“and”条件的绑定比 -o 更紧密,因此这是默认情况,但括号有助于显示正在进行的操作。
运行:
rsync -av --exclude='path1/in/source' --exclude='path2/in/source' [source]/ [destination]
-avr
会创建一个名为[destination]
的新目录。source
和source/
会创建不同的结果:
source
——将source的内容复制到destination中。source/
——将source文件夹复制到destination中。--exclude-from=FILE
——FILE
是包含其他要排除的文件或目录名称的文件的名称。--exclude
也可以包含通配符:
--exclude=*/.svn*
修改自:https://dev59.com/3XI95IYBdhLWcg3wsQL9#2194500
起始文件夹结构:
.
├── 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命令的man手册以获取更多信息。
与Jeff的想法类似(未经测试):
find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/
/usr/share/icons
的子目录中尝试了一下,立即出现了find: paths must precede expression: 22x22
的错误,其中后者是其中一个子目录。我的命令是find . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/
(诚然,我在MSYS2上,所以实际上在/mingw64/share/icons/Adwaita
,但我看不出这是MSYS2的问题)。 - underscore_d简单解决方案(但我仍然更喜欢上面评论中的bash模式匹配方法):
touch /path/to/target/.git
cp -n -ax * /path/to/target/
rm /path/to/target/.git
cp
的-n
选项,强制cp
不覆盖现有目标。cp
。如果没有GNU cp
,则cp
操作可能会返回错误代码(1
),这很烦人,因为你无法确定是否是真正的失败。受 @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"
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
未经测试...
cp -R !(dir1|dir2) path/to/destination
。这将复制除 "dir1" 和 "dir2" 之外的所有内容到指定目的地路径。 - Boris D. Teoharov!(dir1|dir2)
模式需要打开extglob
(使用shopt -s extglob
打开)。 - Boris D. Teoharovcp
命令完成这个操作的方法吗?糟糕透了。 - Alexander Mills