4

除了基本*?[...]模式之外,Bash shell 还提供了扩展的模式匹配运算符,例如!(pattern-list)(“匹配除给定模式之一之外的所有模式”)。extglob需要设置 shell 选项才能使用它们。一个例子:

~$ mkdir test ; cd test ; touch file1 file2 file3
~/test$ echo *
file1 file2 file3
~/test$ shopt -s extglob  # make sure extglob is set
~/test$ echo !(file2)
file1 file3

如果我将 shell 表达式传递给在子 shell 中执行它的程序,则运算符会导致错误。这是一个直接运行子外壳的测试(这里我从另一个目录执行以确保不会过早发生扩展):

~/test$ cd ..
~$ bash -c "cd test ; echo *"
file1 file2 file3
~$ bash -c "cd test ; echo !(file2)"  # expected output: file1 file3
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'

我尝试了各种转义,但我想出的任何方法都没有正常工作。我也怀疑extglob没有设置在子shell中,但事实并非如此:

~$ bash -c "shopt -s extglob ; cd test ; echo !(file2)"
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'

任何解决方案表示赞赏!

4

4 回答 4

4

bash 在执行之前解析每一行,因此当 bash 验证通配模式语法时,“shopt -s extglob”不会生效。不能在同一行上启用该选项。这就是为什么“bash -O extglob -c 'xyz'”解决方案(来自 Randy Proctor)有效并且是必需的。

于 2010-08-12T03:56:03.387 回答
3
$ bash -O extglob -c 'echo !(file2)'
文件 1 文件 3
于 2009-02-09T17:40:46.560 回答
3

这是另一种方式,如果您想避免eval并且需要能够在子外壳中打开和关闭extglob。只需将您的模式放入变量中:

bash -c 'shopt -s extglob; cd test; patt="!(file2)"; echo $patt; shopt -u extglob; echo $patt'

给出这个输出:

file1 file3
!(file2)

证明extglob已设置和未设置。如果第一个echo在 周围有引号$patt,它只会像第二个一样吐出模式echo(可能应该有引号)。

于 2009-06-05T04:47:11.420 回答
1

好吧,我对extglob没有任何真正的经验,但我可以通过将它包装echo在一个中来让它工作eval

$ bash -c 'shopt -s extglob ; cd  test ; eval "echo !(file2)"'
file1 file3
于 2009-02-09T17:34:03.597 回答