Permittivity
Permittivity

Reputation: 97

removing files except some in a bash script

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

Answers (2)

gniourf_gniourf
gniourf_gniourf

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) between shopt -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 the shopt 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

l0b0
l0b0

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

Related Questions