修改 zsh 通配模式以与 cp 一起使用

修改 zsh 通配模式以与 cp 一起使用

我正在尝试编写一个脚本来从除 files 之外的特定文件夹中递归复制文件A.extn,其中B/*.extn和是目录,并且只是一些通用扩展名。这就是我所拥有的:C/*BCextn

#!/usr/local/bin/zsh
setopt EXTENDED_GLOB
TMPDIR=/tmp/test

cp -pR $(dirname $0)/**~(*.foo/*|*/bar.txt|*.abc|qux.txt) $TMPDIR

然而,这并没有按预期对模式进行否定。我想我确实知道为什么 - 尽管模式是正确的(如 所示echo),cp -R但不知道该模式,并且进入了一个“不应该”的目录,并且一旦进入该目录,该模式就不再有效。

我如何修改上面的内容来达到我想要的效果?我想用findand是可能的xargs,但我被上面的清晰性所吸引,并且更喜欢类似的东西(但如果这是错误的方法,我会非常高兴有一个不同的解决方案)。

答案1

您是正确的,该模式在cp运行之前已扩展,因此该命令未知。

您可以通过使用选项--parentstocp而不是 来完成您想要的任务-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

相关内容