我正在尝试编写一个脚本来从除 files 之外的特定文件夹中递归复制文件A.extn
,其中B/*.extn
和是目录,并且只是一些通用扩展名。这就是我所拥有的:C/*
B
C
extn
#!/usr/local/bin/zsh
setopt EXTENDED_GLOB
TMPDIR=/tmp/test
cp -pR $(dirname $0)/**~(*.foo/*|*/bar.txt|*.abc|qux.txt) $TMPDIR
然而,这并没有按预期对模式进行否定。我想我确实知道为什么 - 尽管模式是正确的(如 所示echo
),cp -R
但不知道该模式,并且进入了一个“不应该”的目录,并且一旦进入该目录,该模式就不再有效。
我如何修改上面的内容来达到我想要的效果?我想用find
and是可能的xargs
,但我被上面的清晰性所吸引,并且更喜欢类似的东西(但如果这是错误的方法,我会非常高兴有一个不同的解决方案)。
答案1
您是正确的,该模式在cp
运行之前已扩展,因此该命令未知。
您可以通过使用选项--parents
tocp
而不是 来完成您想要的任务-R
。这只会复制与您的模式匹配的文件,但将使用提供的完整路径名,而不仅仅是尾随文件名。
但是,这个选项不可移植。 AFAIK,只有 GNU 版本的 cp 支持它。
答案2
您的模式可能会排除您不想复制的文件,但它不会排除包含它们的目录,并且您告诉cp
要递归复制。所以无论如何文件都会被复制。比这更糟糕的是,如果你有一个像这样的源代码树
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
然后该模式扩展到,foo hello hello/world hello/world/wibble.txt
因此您最终会在以下位置得到这些文件$TMPDIR
:
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
wibble.txt
world
world/wibble.txt
这与模式“不再有效”无关。该模式由 shell 扩展,cp
只能看到文件列表。
您需要使用可以在进行递归遍历时排除文件的复制工具。
您可以使用 zcp 来实现此目的,但它不会复制目录,也不会自动创建目标目录。完成这项工作最简单的工具是 rsync。帕克斯是另一种选择。
rsync -a --exclude='*.foo/*' --exclude='bar.txt' --exclude='*.abc' --exclude='/qux.txt' $(dirname $0) $TMPDIR