问题
In addition to the basic *
, ?
and [...]
patterns, the Bash shell provides extended pattern matching operators like !(pattern-list)
("match all except one of the given patterns"). The extglob
shell option needs to be set to use them. An example:
~$ 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
If I pass a shell expression to a program which executes it in a sub-shell, the operator causes an error. Here's a test which runs a sub-shell directly (here I'm executing from another directory to make sure expansion doesn't happen prematurely):
~/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)'
I've tried all kinds of escaping, but nothing I've come up with has worked correctly. I also suspected extglob
is not set in a sub-shell, but that's not the case:
~$ 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)'
Any solution appreciated!
回答1:
$ bash -O extglob -c 'echo !(file2)' file1 file3
回答2:
bash parses each line before executing it, so "shopt -s extglob" won't have taken effect when bash is validating the globbing pattern syntax. The option can't be enabled on the same line. That's why the "bash -O extglob -c 'xyz'" solution (from Randy Proctor) works and is required.
回答3:
Here's another way, if you want to avoid eval
and you need to be able to turn extglob on and off within the subshell. Just put your pattern in a variable:
bash -c 'shopt -s extglob; cd test; patt="!(file2)"; echo $patt; shopt -u extglob; echo $patt'
gives this output:
file1 file3
!(file2)
demonstrating that extglob was set and unset. If the first echo
had quotes around the $patt
, it would just spit out the pattern like the second echo
(which probably should have quotes).
回答4:
Well, I don't have any real experince with extglob, but I can get it to work by wrapping the echo
in an eval
:
$ bash -c 'shopt -s extglob ; cd test ; eval "echo !(file2)"'
file1 file3
来源:https://stackoverflow.com/questions/529054/how-to-escape-extended-pathname-expansion-patterns-in-quoted-expressions