假设我想复制目录的内容,不包括名称中包含"音乐"一词的文件和文件夹.
cp [exclude-matches] *Music* /target_directory
什么应该代替[exclude-matches]来实现这个目标?
在Bash中,您可以通过启用该extglob
选项来完成此操作(当然,替换ls
为cp
并添加目标目录)
~/foobar> shopt extglob extglob off ~/foobar> ls abar afoo bbar bfoo ~/foobar> ls !(b*) -bash: !: event not found ~/foobar> shopt -s extglob # Enables extglob ~/foobar> ls !(b*) abar afoo ~/foobar> ls !(a*) bbar bfoo ~/foobar> ls !(*foo) abar bbar
您可以稍后禁用extglob
shopt -u extglob
该extglob
外壳选项可以让你在命令行更强大的模式匹配.
你打开它shopt -s extglob
,然后关闭它shopt -u extglob
.
在您的示例中,您最初会执行以下操作:
$ shopt -s extglob $ cp !(*Music*) /target_directory
全部可用的ext结束的glob bing运算符(摘自man bash
):
如果使用内置shopt启用了extglob shell选项,则会识别多个扩展模式匹配运算符.在以下描述中,模式列表是由|分隔的一个或多个模式的列表.可以使用以下子模式中的一个或多个来形成复合图案:
?(pattern-list)
匹配给定模式的零次或一次*(pattern-list)
匹配给定模式的零次或多次出现+(pattern-list)
匹配给定模式的一个或多个实例@(pattern-list)
匹配给定模式之一!(pattern-list)
匹配除给定模式之外的任何内容
因此,例如,如果要列出当前目录中不是.c
或.h
文件的所有文件,您可以执行以下操作:
$ ls -d !(*@(.c|.h))
当然,正常的shell globing工作,所以最后一个例子也可以写成:
$ ls -d !(*.[ch])
不是bash(我知道),但是:
cp `ls | grep -v Music` /target_directory
我知道这不是你想要的,但它会解决你的例子.
如果你想避免使用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/
在bash中,的替代方法shopt -s extglob
是GLOBIGNORE
variable。并不是真的更好,但是我发现它更容易记住。
原始海报想要的示例可能是:
GLOBIGNORE="*techno*"; cp *Music* /only_good_music/
完成后,unset GLOBIGNORE
就可以rm *techno*
在源目录中了。
您还可以使用一个非常简单的for
循环:
for f in `find . -not -name "*Music*"` do cp $f /target/dir done
我个人的偏好是使用grep和while命令.这允许您编写功能强大且可读的脚本,确保您最终完成您想要的操作.另外,通过使用echo命令,您可以在执行实际操作之前执行空运行.例如:
ls | grep -v "Music" | while read filename do echo $filename done
将打印出您最终要复制的文件.如果列表正确,则下一步是使用copy命令替换echo命令,如下所示:
ls | grep -v "Music" | while read filename do cp "$filename" /target_directory done