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

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
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
  • 4
    What is the syntax to match multiple file names? say I want to exclude .org, .png, .txt ? – Freedo Jan 17 '18 at 1:57
  • @Freedo @() for a pattern-list: stackoverflow.com/a/217208/3779853 – phil294 Aug 22 '19 at 16:51
  • is there a way to do the same when using /bin/sh? – ILIV Nov 21 '19 at 15:32
  • For plain sh, I'd use a for-loop with a case statement inside to decide which files to keep. – glenn jackman Nov 21 '19 at 17:01

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
  • 6
    Note if you want to expand the list of ignored, separate with a colon, such as GLOBIGNORE="*foo*:*bar*" – phyatt May 8 '19 at 18:45

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 '19 at 2:31
  • 1
    Easier to remember (for me, I do that sort of thing often) and allows more complex processing to boot :) – drevicko Jul 4 '19 at 7:17
  • 1
    ls -1 should be more reliable to ensure all files are handled by grep separately – MichaelChirico Sep 23 '19 at 3:30
  • Unfortunately, the side-effect of xargs in this form is that each process (and therefore file) waits to complete before the next process runs. So, in the case of something like xz -T0 multithreaded compression will be limited to within the file which reduces the efficiency considerably on multicore systems. You can add the -P flag to xargs which helps, but still means the compression indexes have to be rebuilt separately for every file. – tu-Reinstate Monica-dor duh Jan 12 at 23:45
  • @MichaelChirico We have find for that, never parse ls output. – val says Reinstate Monica Mar 9 at 10:27

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.