Remove all *.mp4 and *.zip but some files

5,946

Solution 1

The pattern !("file1" | "file2") matches any file except file1␣ or ␣file2 where is a space. The way you quoted it is misleading: it's equivalent to !(file1 | file2) or !("file1 "|" file2)`.

There's no way in bash to combine a negative pattern with a positive pattern to say “all of these except for those”. In zsh, you can write

setopt extended_glob
rm /path/to/directory/*.(mp4|zip)~(keep*|1234.zip)

to remove this.mp4 and that.zip but not keep-this.mp4 or 1234.zip.

In bash, you can set the GLOBIGNORE variable to exclude certain patterns from all matches.

shopt -s extglob
GLOBIGNORE='keep*:1234.zip'
rm /path/to/directory/*.(mp4|zip)
unset GLOBIGNORE

Alternatively, you can use find, which lets you build arbitrarily complex boolean expressions.

find /path/to/directory \( -name '*.mp4' -o -name '*.zip' \) ! -name 'keep*' ! -name '1234.zip' -delete

Note that find recurses into subdirectories. If this isn't desired, add -maxdepth 1 after /path/to/directory.

If your find doesn't understand -maxdepth (it's common but not standard), use -type d -prune -o instead. If your find doesn't understand -delete (same remark), use -exec rm {} + instead.

Solution 2

There are several ways:

  • Use find (portable as it does not need specific shell [bash])
find . -maxdepth 1 ! -name "exclude" -delete

or in case you have several patterns:

find . -maxdepth 1 ! \( -name "exclude" -o -name "exclude2" \) -exec rm -f {} \+
  • Use GLOBIGNORE variable (bash only)
export GLOBIGNORE=exclude:exclude1:mask*

That will exclude mentioned files and masks from globing. After that you can specify rm your_pattern

You can try it before with ls

Share:
5,946

Related videos on Youtube

DrakaSAN
Author by

DrakaSAN

Try to type "about:robots" in Firefox url bar

Updated on September 18, 2022

Comments

  • DrakaSAN
    DrakaSAN almost 2 years

    In one of my programs I call a bash command to remove all files in the directory, but some:

    bash -c
    shopt -s extglob
    shopt -s nullglob
    rm /path/to/directory/!("file1" | "file2")
    

    Which for what I understand mean "Use bash on this command, use the extended pattern, remove all files but those"

    It works good, but deletes every file but the ones put in the command.

    What I would like is to remove all .mp4 and .zip in the directory but the ones I put in the command.

    I think I'll have to add *.mp4 and *.zip somewhere in the command, but I have no idea where.

    EDIT: For clarity, what I need is "Delete all .mp4 and .zip files, but keep thoses"

    • Anthon
      Anthon over 10 years
      have you tried rm /path/to/directory/{*.zip,*.mp4}?
    • jirib
      jirib over 10 years
      Bashism... Bleah. Use find and learn how to make it portable between various system. Why would one need to use bash for such simple goal?
    • DrakaSAN
      DrakaSAN over 10 years
      I am trying with rm /path/to/directory/{*.zip, *.mp4, !("file1" | "file2")
    • DrakaSAN
      DrakaSAN over 10 years
      @Anthon I get rm: missing operand
    • DrakaSAN
      DrakaSAN over 10 years
      @Jiri: Because the app is not meant to be portable. Is there other way to delete a file on raspbian?
    • jirib
      jirib over 10 years
      It's not about your app is not portable. It's about good behaviour. World is not only bash/Linux. Use the strength of bash when it makes really sense but this is not the case. Maybe one day you would sit in front of Solaris, *BSD, AIX... Then what? It's nothing more stupid than bash-based shebang when it is not needed.
    • DrakaSAN
      DrakaSAN over 10 years
      @JiriXichtkniha: And at that moment I ll learn and use equivalent on whatever else system, I only use bash because my full app is in node.js, but I need a quick way to purge all unused files, and the fastest way I found is to use bash.
  • jirib
    jirib over 10 years
    GNUism. Please be more general and use either 'exec rm' or 'xargs rm'. Thanks.
  • DrakaSAN
    DrakaSAN over 10 years
    I m trying it right now, but it seems it will find all files but thoses I exclude, what I need is to find all .mp4 and .zip but thoses I want to exclude.
  • DrakaSAN
    DrakaSAN over 10 years
    For find, where is supposed to be the )? (several pattern)
  • rush
    rush over 10 years
    @DrakaSAN you can use something like find . -name *.ext ! -name 1.ext