假设我想复制一个目录的内容,不包括名称包含单词“音乐”的文件和文件夹。

cp [exclude-matches] *Music* /target_directory

应该用什么来代替[排除匹配]来实现这一点?


当前回答

我个人倾向于使用grep和while命令。这允许您编写强大而可读的脚本,以确保您最终做的正是您想要的。另外,通过使用echo命令,您可以在执行实际操作之前进行演练。例如:

ls | grep -v "Music" | while read filename
do
echo $filename
done

会打印出你要复制的文件。如果列表是正确的,下一步是简单地将echo命令替换为copy命令,如下所示:

ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done

其他回答

如果您想避免使用exec命令的mem成本,我相信您可以使用xargs做得更好。我认为以下是一个更有效的替代

find foo -type f ! -name '*Music*' -exec cp {} bar \; # new proc for each exec



find . -maxdepth 1 -name '*Music*' -prune -o -print0 | xargs -0 -i cp {} dest/

我个人倾向于使用grep和while命令。这允许您编写强大而可读的脚本,以确保您最终做的正是您想要的。另外,通过使用echo命令,您可以在执行实际操作之前进行演练。例如:

ls | grep -v "Music" | while read filename
do
echo $filename
done

会打印出你要复制的文件。如果列表是正确的,下一步是简单地将echo命令替换为copy命令,如下所示:

ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done

我还没有在这里看到一个不使用extglob, find或grep的技巧是将两个文件列表视为集合,并使用comm对它们进行“diff”:

comm -23 <(ls) <(ls *Music*)

Comm比diff更可取,因为它没有额外的麻烦。

返回集合1,ls中不存在于集合2,ls *Music*中的所有元素。这需要两个集合都按顺序排序才能正常工作。ls和glob展开没有问题,但如果使用find之类的东西,一定要调用sort。

comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)

可能有用。

你也可以使用一个非常简单的for循环:

for f in `find . -not -name "*Music*"`
do
    cp $f /target/dir
done

extglob shell选项在命令行中为您提供了更强大的模式匹配。

用shopt -s extglob打开它,用shopt -u extglob关闭它。

在你的例子中,你最初会做:

$ shopt -s extglob
$ cp !(*Music*) /target_directory

完全可用的扩展通配符是(摘自man bash):

If the extglob shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized.A pattern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the following sub-patterns: ?(pattern-list) Matches zero or one occurrence of the given patterns *(pattern-list) Matches zero or more occurrences of the given patterns +(pattern-list) Matches one or more occurrences of the given patterns @(pattern-list) Matches one of the given patterns !(pattern-list) Matches anything except one of the given patterns

因此,例如,如果你想列出当前目录中所有不是。c或。h文件的文件,你会这样做:

$ ls -d !(*@(.c|.h))

当然,普通的shell globing也可以,所以最后一个例子也可以写成:

$ ls -d !(*.[ch])