3

I would like to create a cleanup script for a directory used for backups.

For example: I have 10 files in a directory and they include numbering in the file name

such as:

b_100
b_101
b_102
b_103
b_104
b_105
b_106
b_107
b_108
b_109
b_110

I would like to grep for specific files within the directory from b_105 to b_110 and remove all the rest. Meaning b_100 b_101 b_102 b_103 b_104 will all be removed/deleted.

If I would to grep for one file within a directory like b_110 then remove everything not grepped for.

terdon
  • 242,166
  • 2
    grep searches content inside files. Did you mean that, or did you mean that you simply wanted to match the files named b_105 to b_110 and remove the rest? – Chris Davies Sep 22 '16 at 13:09

5 Answers5

6

With zsh:

setopt extendedglob
rm -rf -- ^b_<105-110>

Would remove all non-hidden files and directories except those whose name starts with b_ and ends in a decimal number whose value is comprised in between 105 and 110.

If you only want to remove b_* files:

rm -rf -- b_(*~<105-110>)

~ being zsh glob operator for except.

Or you could do:

all_b_files=(b_*)
to_exclude=(b_{105..110})
rm -rf -- ${all_b_files:|to_exclude}

With ksh93 or bash -O extglob (or zsh -o kshglob):

set -- b_{105..110} # set positional parameters to b_105 b_106...
IFS='|'             # used for joining positional parameters in "$*"
pattern="$*"        # prepare extended ksh glob
IFS=                # empty IFS to prevent splitting
rm -rf -- !($pattern)
3

With bash and extended globbing enabled, you can do:

shopt -s extglob 
glob=$(echo b_{105..110} | sed 's/ /|/g')
rm -- !($glob)

That will first set the variable glob to the output of:

$ echo b_{105..110} | sed 's/ /|/g'
b_105|b_106|b_107|b_108|b_109|b_110

So, a list of the desired file names separated by a |. Then, the command rm -- !($glob) will remove all files not matching $glob.

terdon
  • 242,166
1

You can use find to list all none matching files in a directory:

find /path/to/directory -not -name "file_name_to_keep" -type f

You can then pipe the output of find into xargs or just use find's built in exec or delete feature.

find /path/to/directory -not -name "file_name_to_keep" -type f -exec rm "{}" \;

or using GNU find's built in delete option

find /path/to/directory -not -name "file_name_to_keep" -type f -delete

More discussion of the various methods of deleting based on find output here: How to delete directories based on `find` output?

1

If you're grepping for a string within the file, you can use -L :

grep -L "string" ./* | xargs rm

Alternatively - as you said you were using this for backups, you could use find to find all files past a certain date old, and remove them with -exec. That would be a better solution than a grep if you are using date-5days for instance.

countermode
  • 7,533
  • 5
  • 31
  • 58
Tim P
  • 11
0

I didn't read the whole question, but when you say "except the grepped items", this immediately makes me think that you don't know the -v grep parameter, which means "Everything except ...", e.g.:

ls -ltra | grep -v .txt

This will show you a list of all files, except the text files.

Dominique
  • 141
  • Everyone, if you downvote, be constructive and comment on why. For example, 'not reading the entire question' is not enough basis, especially when the answer happens to be correct, or at least on the right path. – Pysis Sep 22 '16 at 19:41