Bash Script – Fix Parenthesis Not Working

bashshell-script

I can run this command from my command line prompt:

cp -r folder/!(exclude-me) ./

To recursively copy all contents of folder except for the subdirectory named exclude-me into the current directory. This works exactly as intended. However, I need this to work in a bash script I've written, where I have this:

if [ -d "folder" ]; then
  cp -r folder/!(exclude-me) ./
  rm -rf folder
fi

But when I run the script:

bash my-script.sh

I get this:

my-script.sh: line 30: syntax error near unexpected token `('
my-script.sh: line 30: `  cp -r folder/!(exclude-me) ./'

And I'm at a loss as to why it works from the command prompt, but the exact same line doesn't work in a bash script.

Best Answer

That's because the syntax you're using depends on a particular bash feature which is not activated by default for non-interactive shells (scripts). You can activate it by adding the relevant command to your script:

## Enable extended globbing features
shopt -s extglob

if [ -d "folder" ]; then
  cp -r folder/!(exclude-me) ./
  rm -rf folder
fi

This is the relevant section of man bash:

   If the extglob shell option is enabled using the shopt builtin, several
   extended  pattern  matching operators are recognized.  In the following
   description, a pattern-list is a list of one or more patterns separated
   by a |.  Composite patterns may be formed using one or more of the fol‐
   lowing sub-patterns:

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns
Related Question