How to delete all files in a directory except some?

166,362

Solution 1

What I do in those cases is to type

rm *

Then I press Ctrl+X,* to expand * into all visible file names.

Then I can just remove the two files I like to keep from the list and finally execute the command line.

Solution 2

To rm all but u,p in bash just type:

rm !(u|p)

This requires the following option to be set:

shopt -s extglob

See more: glob - Greg's Wiki

Solution 3

You can use find

find . ! -name u ! -name p -maxdepth 1 -type f -delete
  • ! negates the next expression
  • -name specifies a filename
  • -maxdepth 1 will make find process the specified directory only (find by default traverses directories)
  • -type f will process only files (and not for example directories)
  • -delete will delete the files

You can then tune the conditions looking at the man page of find

Update

  • Keep in mind that the order of the elements of the expressions is significant (see the documentation)
  • Test your command first by using -print instead of -delete

    find . ! -name u ! -name p -maxdepth 1 -type f -print
    

Solution 4

Simple:

mv the files you want in a upper directory, rm the directory and then mv them back.

Solution 5

Somewhat similar to this answer but no special options are needed, as far as I know the following is "ancient" functionality supported by any (vaguely) /bin/sh resembling shell (e.g. bash, zsh, ksh, etc)

rm [^up]
Share:
166,362
Ashot
Author by

Ashot

Updated on September 18, 2022

Comments

  • Ashot
    Ashot over 1 year

    I need to delete all files in a directory, but exclude some of them. For example, in a directory with the files a b c ... z, I need to delete all except for u and p. Is there an easy way to do this?

    • Joe
      Joe over 11 years
      The answers below are a lot better, but you could just make the files to save read-only, delete all, and then change them back to their original permissions (as long as you don't use rm -f). You'd have to know what permissions to restore and you'd have to know that nothing needed write access to them during the process. This is why the other answers are better.
    • Admin
      Admin over 11 years
      If you also want to delete hidden files run shopt -s dotglob before running rm (...).
  • slhck
    slhck over 11 years
    You need to shopt -s extglob, @Ashot. Also, it's just files, not directories, which is why I've removed the -rf options in your command.
  • glenn jackman
    glenn jackman over 11 years
    This works for the 1-char filenames. For longer names, sparkie's answer is better.
  • user
    user over 11 years
    What would be wrong with rm [^up]*? I do similar things rather often.
  • Frerich Raabe
    Frerich Raabe over 11 years
    I guess this works only as long as the list of files which * expands too isn't getting too long. :-}
  • Oliver Salzburg
    Oliver Salzburg over 11 years
    @FrerichRaabe: Indeed. If it's too long a different approach will be required. Luckily we now have a list of great options :)
  • Michał Šrajer
    Michał Šrajer over 11 years
    order of predicates is critical here. If one put -delete just after . it will be disaster (will delete all files in CWD)
  • kojiro
    kojiro over 11 years
    This could be written more compactly as find . -maxdepth 1 -type f -name '[^up]' -delete
  • user
    user over 11 years
    This does not work on my shell (GNU bash 4.1.5(1)). Be sure to test it first with something a little less harmful than rm or in a testing directory!
  • Matteo
    Matteo over 11 years
    @kojiro yes but only for files that are just one letter. With more complex names the regex could be a mess.
  • reinierpost
    reinierpost over 11 years
    @Konerak: rm without -r won't remove subdirectories.
  • John S
    John S over 11 years
    @MichaelKjörling - this would delete all files beginning with either u or p, not just those with the names u and p. I think the OP (@Ashot) meant the a-z and u,p,etc. symbolically and not literally.
  • hlascelles
    hlascelles over 11 years
    It reminded me the same thing. But temporarily moving out of folder may not be a good idea in the era of multitasking :)
  • Matteo
    Matteo over 11 years
    You need to specify a directory before the expression (`find . -regextype ...).
  • Matteo
    Matteo over 11 years
    -regextype will only work on GNU versions
  • Matteo
    Matteo over 11 years
    grep will not handle extended regexpt by default: either use -E or egrep
  • Matteo
    Matteo over 11 years
    This will overwrite files with the same name in the destination directory
  • sparkie
    sparkie over 11 years
    no - my find version (debian squeeze) does definitively not require an explicit directory before the expression if the current directory should be used
  • Matteo
    Matteo over 11 years
    @sparke: this just works on GNU implementations
  • rjmunro
    rjmunro over 11 years
    @Matteo No it won't. The grep isn't grepping the files, it's grepping the output of the ls command. You're thinking of something like grep -L (u|p)' * | xargs rm where -L means list filenames not containing a match.
  • rjmunro
    rjmunro over 11 years
    Oh, you mean any file who's name contains u or p, not any file containing a u or a p. That is correct. You can fix by using egrep -v '^(u|p)$'
  • anjaly
    anjaly over 11 years
    Esc followed by * will also expand the "*".
  • Terence Johnson
    Terence Johnson over 11 years
    find is my best friend, especially when there are too many files to glob
  • sam hocevar
    sam hocevar over 11 years
    I am downvoting this because while it can be handy, it also is non-atomic and effectively removes all files from the directory during a short period of time; this would not be acceptable if, for instance, the files are being shared on the network.
  • Santosh Kumar
    Santosh Kumar over 11 years
    This only works with rm; was looking for mv, cp, chmod etc.. :(
  • Oliver Salzburg
    Oliver Salzburg over 11 years
    @SantoshKumar: That doesn't make sense to me. The expansion will always work, it doesn't depend on what command you want to use afterwards.
  • Santosh Kumar
    Santosh Kumar over 11 years
    @OliverSalzburg Sorry, the combination is little bit confusing. I think you should write like Ctrl + Shift + x + *
  • Oliver Salzburg
    Oliver Salzburg over 11 years
    @SantoshKumar: But that's not the combination.
  • Nick
    Nick over 9 years
    Here is remove everything except these matches! ls | grep -v 'vuze\|progs' | xargs rm -rf
  • flungo
    flungo about 9 years
    Works in practice but can't be scripted. I think the find solution is the best.
  • mzuther
    mzuther almost 9 years
    If you need to exclude one file of a selection of files, try this: rm !(index).html. This will delete all files ending in ".html" with the exception of "index.html".
  • Mikko Rantalainen
    Mikko Rantalainen over 8 years
    @sparkie: not defining the directory (first parameter) for find is a GNU extension of find command. The same applies for -regextype option. In addition, your command will delete files in subdirectories, too, whereas the original question clearly asked about files in a directory.
  • Forever Learner
    Forever Learner over 6 years
    @Oliver Salzburg, the combination is not working on my Korn shell , what I might be doing wrong could you please advise? solution from slowpoision , esc followed by * worked though. Thanks
  • Jan Heinrich Reimer
    Jan Heinrich Reimer about 4 years
    Also you'd need write access on the parent directory, which you likely not have on a shared web server.
  • Mohan Munisifreddy
    Mohan Munisifreddy about 4 years
    +1 for the explanation of all arguments
  • david
    david over 2 years
    +1 as it works with sh vs rm fashion