I have a list of files in the following fashion:

> file1.jpg 
> file1_orig.jpg 
> file2.jpg 
> file2_orig.jpg

I want to keep all the files with the extension _orig.jpg and discard those without. How can this be achieved using bash?

  • Are they in a single directory? – Sparhawk Aug 17 '14 at 10:24

You can use Bash's extended filename expansion:

rm !(*_orig.jpg)

The !(pattern) syntax:

Matches anything except one of the given patterns.

so this expands to all filenames that don't match *_orig.jpg, which you can delete (or move out of the way). You need to have the extglob option enabled, which you can do with shopt -s extglob beforehand (otherwise you will get an error of the form "event not found"). It is commonly enabled by default, though.

Alternatively, and portably, you can just move the files you want to keep out of the way temporarily and delete the rest:

mkdir tmp
mv *_orig.jpg tmp
rm *.jpg
mv tmp/*.jpg .
rmdir tmp

There are options using find as well:

find . -type f ! -name '*_orig.jpg' -exec rm '{}' +

That will find any (regular) files recursively in the current directory that are not named *_orig.jpg and delete them; this is your best (but not only) option if the files aren't all directly inside one directory.

  • 1
    Dammit, I was half through my answer. :) Just as an aside, you can check to see if extglob is enabled with $ shopt | grep extglob. Also -execdir is preferred for find for security reasons (see man find). Oh, and also you can check and make sure you've picked the right files before removing them with ls !(*_orig.jpg) and find . -type f ! -name '*_orig.jpg'. +1 – Sparhawk Aug 17 '14 at 10:30
  • shopt extglob will tell you directly. -execdir is a non-standard extension and doesn't really resolve any security issues here. – Michael Homer Aug 17 '14 at 10:35
  • Good points. I didn't realise -execdir was non-POSIX and only GNU. FWIW here is a theoretical example of an attack, which is admittedly unlikely here; however, I always use -execdir as good practice. – Sparhawk Aug 17 '14 at 10:38

POSIX way:

$ find . \( ! -name . -prune -a -name "*.jpg" -a ! -name "*_orig.jpg" \) -exec rm -- {} +

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.