如何在引用的表达式中转义扩展路径名扩展模式?

时间:2009-02-09 17:20:34

标签: bash escaping design-patterns expansion

除了基本的*?[...]模式之外,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中执行它的程序,则运算符会导致错误。这是一个直接运行子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 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:3)

$ bash -O extglob -c 'echo !(file2)'
file1 file3

答案 2 :(得分:3)

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

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

给出了这个输出:

file1 file3
!(file2)

证明 extglob 已设置并取消设置。如果第一个echo$patt附近有引号,它就会像第二个echo(可能应该有引号)一样吐出模式。

答案 3 :(得分:1)

好吧,我对 \ textglob 没有任何实际经验,但我可以通过将echo包裹在eval中来实现它:

$ bash -c 'shopt -s extglob ; cd  test ; eval "echo !(file2)"'
file1 file3