46

I have several files with the same base filename. I'd like to remove all but one

foo.org #keep
foo.tex #delete
foo.fls #delete
foo.bib #delete
etc

If I didn't need to keep one, I know I could use rm foo.*.

TLDP demonstrates ^ to negate a match. Through trial and error, I was able to find that

rm foo.*[^org]

does what I need, but I don't really understand the syntax.

Also, while not a limitation in my use case, I think this pattern also ignores foo.o and foo.or. How does this pattern work, and what would a glob that ignores only foo.org look like?

  • 1
    As an addition to @glen answer it is worth to mention that rm foo.*[^org] removes all files which last character is neither o, r or g, so foo.foo wouldn't match either. – jimmij Oct 24 '14 at 16:04
  • You are using a Regular Expression. You should be careful with your grouping characters. By using brackets you've specified a character class meaning that you would delete any files that had an extension with the letters o,r or g in any order. Use parenthesis to create a group and preserve the order of characters. – Mr. Mascaro Oct 24 '14 at 17:16
  • 3
    @jbarker2160 - that's not really a regular expression, it's more commonly called a glob (or filename pattern), which is more or less a subset of a regular expression - see the pattern matching section of the bash manpage for details. His pattern foo.*[^org] will match any filename that begins with foo. with one or more characters after the dot where the last character is not o, r, or g. So it would match foo.orb, but not foo.org or foo.or or foo.o. GlennJackman's answer shows how to enable extended pattern matching features to negate a match. – Johnny Oct 24 '14 at 17:33
48
shopt -s extglob
echo rm foo.!(org)

This is "foo." followed by anything NOT "org"

ref: https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching

  • I tried doing the same but with brackets and apparently when using brackets it does not work – Donato May 26 '15 at 15:40
  • 3
    What is the syntax to match multiple file names? say I want to exclude .org, .png, .txt ? – Freedo Jan 17 '18 at 1:57
20

In bash, you can also use GLOBIGNORE="*.org"; rm -i foo*.

And unset GLOBIGNORE when done.

It's not really better than shopt -s extglob, but I find it easier to remember.

  • 5
    @Ruslan That doesn't work. You should do ( GLOBIGNORE="*.org"; rm -i foo* ) – DBedrenko Mar 9 '17 at 11:20
  • 2
    Note if you want to expand the list of ignored, separate with a colon, such as GLOBIGNORE="*foo*:*bar*" – phyatt May 8 at 18:45
6

A pipe can do?

ls * | grep -v "foo.org" | xargs -I {} echo {}

(obviously you might want to replace echo with rm in the last chain).

  • Useful if needed in just one line. – bruceskyaus Jan 1 at 2:31
  • Easier to remember (for me, I do that sort of thing often) and allows more complex processing to boot :) – drevicko Jul 4 at 7:17

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.