Caden Mitchell
Caden Mitchell

Reputation: 133

Unable to exclude a single file from getting deleted after enabling bash extglob

So I've been working on a script for the past few days and have come across this horrible issue! I am trying to delete all the contents of a folder except for one single file. I've enabled the "extglob" shell option already in the bash script with shopt -s extglob and I've setup my commands correctly to my knowledge. Here's an example of my issue:

#!/bin/bash
drive=$1
outpath=/media/removable/$drive/test

shopt -s extglob
if [[ $2 = "Delete" ]];then
    rm -rvf $outpath/* !($outpath/save.tar)
# Also tried this:
#   rm -rvf !($outpath/save.tar) $outpath/*
      exit
fi

(Not my actual file but an example.)

My directory was set to / and for some reason it started deleting every single file in my root directory that it had permission to damage. I don't particularly care about recovering from this, my script is simply not working and I can't get it to exclude this one file. I've tried the example above, I've tried rm -rvf $outpath/* $outpath/!(save.tar) and nothing seems to work. Does anyone know how to properly use the ~("path/to/file") to exclude a file/path? Particularly while using variables to define the path?

Upvotes: 1

Views: 57

Answers (1)

Inian
Inian

Reputation: 85683

Assuming save.tar is inside the test folder, you don't need to use a separate path to exclude the file from getting deleted. The negate operator already globs all the files except the one you provide inside !().

You can just do

rm -rvf "$outpath"/!(save.tar)

Or if you multiple .tar files which need to be excluded, you can move the glob inside the negation as !(*.tar) which means delete everything except the files ending with .tar

A simple reproducible example of your problem is below. Here all the files except file6 are commanded to be deleted and works as expected.

$ mkdir -p /tmp/foo/bar/test
$ touch /tmp/foo/bar/test/file{1..7}
ls /tmp/foo/bar/test/
file1  file2  file3  file4  file5  file6  file7
$ outpath=/tmp/foo/bar/test
$ rm -rvf "$outpath"/!(file6)
removed ‘/tmp/foo/bar/test/file1’
removed ‘/tmp/foo/bar/test/file2’
removed ‘/tmp/foo/bar/test/file3’
removed ‘/tmp/foo/bar/test/file4’
removed ‘/tmp/foo/bar/test/file5’
removed ‘/tmp/foo/bar/test/file7’

See more on bash extended globbing.

Upvotes: 2

Related Questions