我如何使用逆或负通配符时,模式匹配在Unix / Linux的壳呢?我如何使用逆或负通配符时,模式匹

2019-05-09 01:08发布

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

cp [exclude-matches] *Music* /target_directory

应该在的地方[排除百搭]的去怎么做到这一点?

Answer 1:

在bash,那么你可以通过启用做extglob选项,就像这样(取代lscp并加入目标目录,当然)

~/foobar> shopt -s extglob
~/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


Answer 2:

extglob外壳选项可以让你在命令行更强大的模式匹配。

你打开它shopt -s extglob ,并与关闭它shopt -u extglob

在你的榜样,你会做初步:

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

全部可用分机结束水珠兵运营商(摘自man bash ):

如果extglob外壳选择是使用内建命令shopt启用,几个扩展模式匹配运营商的认可。 在以下描述中,轻拍燕鸥列表是由一个分隔的一个或多个模式的列表|。 复合模式可以使用一个或多个下列子图案形成:

  • ?(模式列表)
    匹配零个或一个发生所述给定图案的
  • *(模式列表)
    匹配零和或多个给定模式
  • +(模式列表)
    匹配给定模式中的一个或多个出现
  • @(模式列表)
    匹配给定的模式之一
  • !(模式列表)
    匹配任何东西,除了给定的模式之一

因此,举例来说,如果你想列出所有在当前目录中不属于文件.c.h文件,你会怎么做:

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

当然,一般的外壳globing作品,所以最后一个例子也可以写成:

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


Answer 3:

未在bash(我知道的),但是:

cp `ls | grep -v Music` /target_directory

我知道这不正是你要找的,但它会解决你的榜样。



Answer 4:

如果你想避免使用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/


Answer 5:

在bash中,替代shopt -s extglobGLOBIGNORE变量 。 这不是真的好,但我觉得它更容易记住。

可能是楼主想要的东西的一个例子:

GLOBIGNORE="*techno*"; cp *Music* /only_good_music/

完成后, unset GLOBIGNORE能够rm *techno*源目录。



Answer 6:

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

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


Answer 7:

我个人的偏好是使用grep和同时命令。 这可以写出功能强大,可读的脚本,确保你最终究竟做你想要什么。 此外,通过使用echo命令就可以进行实际操作之前进行试运行。 例如:

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

将打印出来,你最终会复制这些文件。 如果该列表是正确的下一步是简单地复制命令代替echo命令如下:

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


Answer 8:

这其中的一个解决方案可以与find找到。

$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt

查找有相当多的选项,你可以得到你所包括和排除非常具体。

编辑:亚当在评论中指出,这是递归的。 查找选项mindepth和MAXDEPTH可以在控制这个有用。



Answer 9:

我还没有看到这里还没有使用特技extglobfind ,或者grep是处理两个文件列表作为集和“差异”使用这些comm

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

comm是在最好diff ,因为它没有多余的残余。

这将返回集1的所有元件ls ,那是不是也中集2, ls *Music* 。 这既需要设置要在排序才能正常工作。 对于没有问题ls和水珠扩张,但如果你正在使用类似find ,一定要调用sort

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

潜在有用的。



Answer 10:

下面的工作列出了所有*.txt文件在当前目录下,除了那些以数字开头。

这部作品在bashdashzsh和所有其他POSIX兼容的炮弹。

for FILE in /some/dir/*.txt; do    # for each *.txt file
    case "${FILE##*/}" in          #   if file basename...
        [0-9]*) continue ;;        #   starts with digit: skip
    esac
    ## otherwise, do stuff with $FILE here
done
  1. 在一个线条图案/some/dir/*.txt将导致for循环遍历所有的文件/some/dir名称以结束.txt

  2. 在两个线路的情况下,语句用来淘汰不需要的文件。 -在${FILE##*/}表达剥掉从文件名(这里的任何领先的目录名称组件/some/dir/ ),以便patters可以匹配只针对文件的基本名称。 (如果你只淘汰基于后缀文件名,可以缩短这$FILE代替。)

  3. 三线,匹配的所有文件case模式[0-9]* )线将被跳过(在continue语句跳转到的下一个迭代for循环)。 -如果你愿意,你可以做一些更有趣的有,例如像使用跳过不以字母开头的所有文件(AZ) [!az]* ,或者你可以使用多种方式来跳过几种文件名如[0-9]*|*.bak跳过这两个文件.bak文件和文件,不以数字开头。



Answer 11:

这将做到这一点正好除外“音乐”

cp -a ^'Music' /target

这和排除喜欢音乐的东西?*或*?音乐

cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target


文章来源: How can I use inverse or negative wildcards when pattern matching in a unix/linux shell?