Parenthesis works in bash shell itself, but not in bash 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.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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

Method 2

Add this line near top of your script:

shopt -s extglob

!(...) is an extended pattern matching feature, you need extglob option enable to use it. See shopt builtin for more details.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x