How to avoid extended path extension patterns in quoted expressions?

In addition to the basic patterns * ? and [...] the Bash shell provides advanced pattern matching operators, such as !(pattern-list) ("match all but one of the given patterns"). The extglob shell parameter must be set to use them. 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 that runs it in a sub-shell, the operator throws an error. This runs a test that launches the sub-shell directly (here I run from another directory to make sure that the extension does not 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 tried all kinds of shielding, but nothing that I came up with worked correctly. I also suspected that extglob not installed in the sub-shell, but this is 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 is appreciated!

+4
source share
4 answers
  $ bash -O extglob -c 'echo! (file2)'
 file1 file3
+3
source

bash parses every line before executing it, so "shopt -s extglob" will not take effect when bash checks the syntax of a globe template. The option cannot be enabled on the same line. That is why the "bash -O extglob -c" xyz "solution (from Randy Proctor) works and is required.

+4
source

In another way, if you want to avoid eval , and you need to turn extglob on and off inside the subshell. Just put your template in a variable:

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

gives this result:

 file1 file3 !(file2) 

demonstrating that extglob was installed and not installed. If the first echo had quotes around $patt , it would just spit out the pattern, like the second echo (which probably should have quotes).

+3
source

Well, I have no real experience with extglob, but I can get it to work by wrapping echo in eval :

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

All Articles