52

This question already has an answer here:

Here is the situation.

I have a directory which contains many files with different extensions. I want to delete all files except one with a specific name.

This could be easily done using the GUI by selecting all and pressing ctrl and deselecting the file in question.

That is exactly what I want to, but how can I do it from the command line?

For example: dirA contains the following files:

a.txt
b.txt
c.php
d.html
a.db
b.db
e.html

I want to delete all files keeping only the file named a.txt.

marked as duplicate by αғsнιη, Avinash Raj, karel, A.B., user364819 May 18 '15 at 15:25

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    I think this might explain. ;) – JoKeR May 16 '15 at 12:20
  • I've come to this before, but this needs more work – Maythux May 16 '15 at 12:21
  • These questions are confusing me, not to mention they have no idea how many files are on your system with . Or .txt, use this command simple to use and easy to understand rm -riv ~/Desktop/path/* * = all in folder , r = recursive , v = verbose , i = prompt you before deleting – user610658 Apr 9 '17 at 23:56
87

I've come with this easy simple great command:

rm !(a.txt)

you can use ! as a negation

Test the glob with echo first i.e.

echo !(a.txt)

If it doesn't work, for bash you may need to enable this with

shopt -s extglob

If you wanted to keep both a.txt and b.txt, you can use !(a.txt|b.txt) or !([ab].txt).

Edit:

to make rm working recursively just add -r like

rm -r !(a.txt)

and also, it is working with folder. just need to change the name to the dir name, such as for a_dir

rm -r !(a_dir)
  • 1
    What shell does this work on? Does it work on ubuntu's default bash? EDIT: nevermind, found the info, proposed an edit. – Random832 May 16 '15 at 15:19
  • 2
    Seems to be dependent on ksh. Bash doesn't like it. – Joshua May 17 '15 at 16:16
  • 2
    Just to be explicit, is it recursive (affects sub folders)? – Peter Mortensen May 17 '15 at 18:36
  • 1
    @PeterMortensen, you can add -r to rm command like this rm -r !(a.txt), it will work recursively – lhrec_106 Jun 9 '16 at 6:12
  • 1
    For me running this on mac it returns -bash: !: event not found – Jim Mar 17 '17 at 18:57
19

You can try this command:

find . \! -name 'a.txt' -delete

But you need be careful because find command is recursive.

  • 7
    You can prevent find from being recursive with a -maxdepth 1 – evilsoup May 16 '15 at 16:57
  • 1
    Re "because find command is recursive.". Indeed, the other answerers failed to mention that. – Peter Mortensen May 17 '15 at 18:35
11

You can do this in terminal:

cd dirA 
export GLOBIGNORE=a.txt
rm *
export GLOBIGNORE=
  • Does not work if you set full path – kinORnirvana Nov 24 '15 at 9:24
5

You can use the command :

find ! -name 'a.txt' -type f -exec rm -f {} +

This will look for files (-type f) in the current directory except for file a.txt (! -name 'a.txt) and then will remove them (-exec rm -f {} +)

  • But this would not remove the directories if exist?! – Maythux May 21 '15 at 16:36
  • @Maythux Yes, the author asks how to remove files, not folders. – shaddy May 21 '15 at 16:50
  • -exec rm -f {} + doesn't really have any advantages over -delete. – Eliah Kagan Sep 13 '17 at 8:46
4

Use find and xargs

find folder -type f -not -name 'a.txt' -print0 | xargs -0 rm

To exclude multiple things:

find folder -type f -not -name 'a.txt' -not -name 'b.txt' -print0 | xargs -0 rm

This also works with wildcards:

find folder -type f -not -name '*.png' -not -name 'b.txt' -print0  | xargs -0 rm

To search in the current folder, use . in place of 'folder'.

Base source

  • Probably will be good for portability =) +1 – Sergiy Kolodyazhnyy May 16 '15 at 13:42
  • 2
    Note that this will fail if your file names contain whitespace or newlines or glob characters etc. Use find . -type f -not -name 'a.txt' -delete instead. – terdon May 16 '15 at 13:45

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