Search code examples
bashglob

glob pattern in bash don't recognize '('


When running the following command:

rm -rf !(file1|file2)

all files except file1 and file2 are removed; as intended. When either placing this command in a bash script:

#!/bin/bash
rm -rf !(file1|file2)

or running it using bash -c:

bash -c "rm -rf !(file1|file2)"

I receive the following error:

syntax error ner unexpected token '('

I have tried setting the shell options using

shopt -s extglob

yeilding in:

bash -c "shopt -s extglob; rm -rf !(file1|file2)"

to enable glob according to: https://superuser.com/questions/231718/remove-all-files-except-for-a-few-from-a-folder-in-unix and some other questions as well.

Still it doesn't work, and I'm at loss.


Solution

  • First of all, for safety, let's do our testing with echo !(file1|file2) instead of rm -rf !(file1|file2).

    Anyway, bash does some parsing of the entire command line before executing the shopt -s extglob command. When bash encounters the (, the extglob option isn't set yet. That's why you get the error.

    Try this instead:

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

    In your script, you just need to turn on the option as a separate command line before relying on it:

    #!/bin/bash
    shopt -s extglob
    echo !(file1|file2)
    

    You can actually do this with the -c flag also:

    bash -c 'shopt -s extglob
    echo !(file1|file2)'
    

    Or even like this:

    bash -c $'shopt -s extglob\necho !(file1|file2)'