I need to remove all the files in a directory except for one file and one folder. Up to the grep I can output the correct list of items I want to remove but when i add xags, nothing is deleted.

this is the command I'm using.

ls domain.com/wp-content/themes | grep -v -E 'twentyeleven|index.php'  | xargs rm -rf
  • Thank you but that thread does not do exactly as I need, or at least does not go in detail on how to : keep multiple files, keep both files and directories, specify a directory path. – Sebastien Oct 5 '11 at 7:41
  • For multiple files, maybe this: shopt -s extglob; rm !(twentyeleven|index\.php) – Prince John Wesley Oct 5 '11 at 8:17

you could solve this with some more diagnosis,

the command does work in practice, on a simple example.

So all you have to do is a bit of troubleshooting.

It looks like you have done troubleshooting to the point of finding ls domain.com/wp-content/themes | grep -v -E 'twentyeleven|index.php'
looks good.

Try ls file1 file2 file3 from within that directory. | rm -rf

Try echo file1 file2 file3 | rm -rf

Try another directory, maybe there's some issue with that. Basic troubleshooting will take you much further possibly to the solution.

Here is an example that works. Tested in cygwin.

user@iar ~/aa
$ ls | grep -v -E "op"

user@iar ~/aa
$ ls | grep -v -E "op" | xargs rm -rf

user@iar ~/aa
$ ls

user@iar ~/aa

First of all, you want to use ls -1 (number 1, not lowercase L) if you want to use grep on it's output.

But the main problem is, that you list the contents of a subdirectory, but the rm command is executed in the current directory.

For example see this directory tree (. and .. entries omitted)


Let's say you want to remove all from directory a except file y and use the command as you tried:

 $ ls -1 a | grep -v 'y'  | xargs rm -rf

ls -1 a gives:


grep filters out the line with y:


so xargs excutes the following command:

 rm x z

But it executes the command in the top-level directory and sees only directory a, not the files x and z.

In order to make it work, you need the path of the files - easily achieved by applying a minor change to the ls command. Also we refine the grep pattern a bit:

 ls -1d a/* | grep -v '/y$'  | xargs rm -rf

So this time ls produces the following output:


and the final command executed would be rm -rf a/x a/z

So now let's go back to your command line and apply the discussed changes:

 $ ls -1d domain.com/wp-content/themes/* | grep -v -E '/twentyeleven$|/index.php$'  | xargs rm -rf

One last note: Using xargs rm -rf is always venturesome (although sometimes neccessary) - be sure to check the output of the grep command first!

  • interesting.. though regarding the need to do -1, and I see -1 makes sense if | grep, but it works without it too. If I do $ls<ENTER> it lists 5 files: er op qw ty ui It lists them on one line. And if I do $ls | od -c I actually see \n in between each of them. Infact ls -1 | od -c looks like it dumps the same output as ls | od -c Just the \n is interpreted as new line in the case of ls -1 , but \n is still there with ls without -1. – barlop Oct 5 '11 at 14:11
  • @barlop: But one should not assume that this is true in every environment - whereas 'ls -1' is a standard option with a standard outcome (one file per line). – ktf Oct 5 '11 at 14:39
  • well, maybe ls including \n is standard on all *nix systems, I don't know, and if it is, then -1 is completely unnecessary! I see a thing worth noting about your method, is with globbing which you've used, it introduces something which isn't standard, some systems may be set to include . and .. (dot and dotdot) some may not, which I suppose then get expanded like (dotdot colon) ..: then the files there. And if (dotdot).. were to go literally to rm -rf , I guess it wouldn't but if it did then it's dangerous and not very portable to some systems! – barlop Oct 5 '11 at 16:47
  • Globbing files starting with a dot would be non-standard, too ;-) – ktf Oct 6 '11 at 8:47
  • yes i'm all for the consideration of catering to non-standard. But in the case of ls without -1, I don't know if there are *nix systems where the output doesn't have a \n. Whereas in the case of globbing, I know for example bash has an option to make globbing include . and .. that's my point, and the distinction there. Also (and i'm not relying on this, but just as a side thing) it's quite a possibility that it's default to do so in some shells 'cos I vaguely recall possibly seeing a shell script demonstrating that. – barlop Oct 6 '11 at 11:11

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.