Reputation: 97
I was trying to delete some files in a bash script and exclude some I still need afterwards. This is what I came up with:
if [ $var1 -eq 0 ]; then
echo "$var1 = 0"
shopt -s extglob
rm /home/someone/!(file1.txt|file2.png|file3.pdf|file4.csv)
else
echo "$var1 = 1"
shopt -s extglob
rm -rf /home/someone/!(file1.txt|file2.png|file3.pdf|file4.csv)
fi
It is working if I execute it manually on the shell, but in the script it does not even call the if-loop. As soon as I comment out the lines containing the "!" it works.
Upvotes: 1
Views: 366
Reputation: 46823
You cannot turn the extglob
shell option from within a block or a function. E.g., this will fail:
shopt -u extglob
f() {
shopt -s extglob
echo *+(a)*
}
f
The reason is that the command shopt -s extglob
is not executed when the block is parsed… and the parser will hence complain when it encounters the extended glob +(a)
. See the relevant section of the glob
page on Greg's wiki:
extglob
changes the way certain characters are parsed. It is necessary to have a newline (not just a semicolon) betweenshopt -s extglob
and any subsequent commands to use it. You cannot enable extended globs inside a group command that uses them, because the entire block is parsed before theshopt
is evaluated. Note that the typical function body is a group command. An unpleasant workaround could be to use a subshell command list as the function body.
If you really want this behavior, though, you can use eval
, but that's really not recommended at all! Instead, move the shopt -s extglob
out of the block. In fact, it is customary to put the shell options at the beginning of the script and use them throughout the script (when applicable). I don't think you'll run into any problems if you use extglob
throughout the script.
Upvotes: 1
Reputation: 58808
As @choroba is hinting towards, you need to run your script either as bash my_script.sh
or ./my_script.sh
to run it with Bash. If you run sh my_script.sh
the shell may not support extglob
.
A useful way to tell what's actually happening is to add set -o xtrace
to the top of the script (after the shebang line). That should tell you what actually gets executed. I'd also add set -o errexit
to make sure the script stops at the first failing command, and quote the reference to $var1
.
Upvotes: 0