Tutorial :How to escape extended pathname expansion patterns in quoted expressions?



Question:

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!


Solution:1

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


Solution: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.


Solution: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).


Solution: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  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »