82

Is there a command to remove all files and subdirectories in a directory without deleting the directory?

For example if I have directory dontDeleteMe with subdirectories 1, 2, 3 and each subdirectory has a few pictures in it, how can I remove the subdirectories 1, 2, and 3 and all the files in the them, without removing the parent directory dontDeleteMe?

Eliah Kagan
  • 119,820
user784637
  • 11,475

13 Answers13

93

To remove everything in a directory without removing the directory, type in:

rm -rfv dontDeleteMe/*

Please note, the /* part is very important. If you put a space before the *, it will delete all your files in your current directory.

Also, be very careful playing with rm, -r and * all in the same command. They can be a disastrous combination.

Update: Okay, I realized if you do have hidden/dot files [filenames with dots at the beginning, e.x. .hidden] then this will leave those files intact.

So really, the simplest solution to the original question is:

rm -rfv dontDeleteMe && mkdir dontDeleteMe

Another one would be to use find's -exec option or pipe to xargs (below):

find dontDeleteMe/* -print0  | xargs -0  rm -rv
pomsky
  • 70,797
Matt
  • 10,231
  • Can you give an example of using xargs? What is xargs? – 0xnuminous Nov 01 '11 at 18:55
  • @justingrif: find dontDeleteMe/* -print0 | xargs -0 rm -rv I believe in most cases this will work, regardless of spaces, and what not. But cd to /tmp/ and make a test directory and try it out. :) – Matt Nov 01 '11 at 22:42
  • Oh, and from the manpage: "xargs - build and execute command lines from standard input" – Matt Nov 01 '11 at 22:52
  • 6
    Re-making a directory does not equal deleting its contents. e.g. umask directory permission differences, owner differences, etc... enzotib's answer would solve the issues with your original syntax –  Oct 09 '14 at 20:43
  • 6
    This is not a good answer. Using * is dangerous, and won't work on dotfiles without "dotglob" (see below). rm -rf dontDeleteMe && mkdir dontDeleteMe doesn't ensure that the dir is re-created with the same permissions/owner(s). Instead, use one of the find dontDeleteMe/ -mindepth 1 -delete variants below. – Nils Toedtmann Jan 15 '15 at 13:31
  • 1
    @NilsToedtmann, with all due respect, I did give fair warning in my answer that the * should be used with care. – Matt Feb 10 '15 at 21:34
  • @Matt While this warning is "fair", a really good answer would put the preferable solution at the top, rather than keeping a questionable solution at the beginning, then adding a warning to it, followed by another questionable solution, and providing the only proper solution at the very end of the answer. – vog Jul 11 '25 at 06:47
48

Open terminal (Ctrl+Alt+T) ant type this:

find somedir -mindepth 1 -delete

This will match all files and directories within somedir and its (grand-)children including "hidden" dot files but excluding somedir itself because of -mindepth 1, then -delete them.

David Foerster
  • 36,900
  • 56
  • 98
  • 152
guciek
  • 481
  • This works well for me, although is it fundamentally safer than using "rm -rf"? – Eric P May 25 '22 at 08:59
  • 2
    @EricP The main difference between find with -mindepth 1 and rm is that the former will keep the directory and only delete its contents. It's not safer per se, both will delete everything in the directory without confirmation if you have the permissions to do so. But find is more flexible (it has many more options than rm). – Dario Seidl Jun 07 '22 at 13:51
  • Also working nicely with patterns: find */web/sites/default/files -delete – norman.lol May 14 '23 at 15:43
  • You might want to add -xdev for improved safety. – vog Jul 11 '25 at 07:45
32

The only reason rm -r ./* do not always work is because you can have hidden files and/or folder that are not matched by *.

To this end, bash provide an option to make * match everything, even hidden objects:

cd dont-delete-me
shopt -s dotglob
rm -r ./*

It can be useful to reset dotglob to its default (unset) state, if you keep on using the shell where you executed the above commands:

shopt -u dotglob 
enzotib
  • 96,253
5
find /dontDeleteMe/ -xdev -depth -mindepth 1 -exec rm -Rf {} \;

Use xdev option to delete files only within device boundary.

Sergey
  • 1,179
  • 2
    GNU find has -delete. It implies -depth and is easier to remember than -depth -exec rm -Rf {} \; – Nils Toedtmann Jan 15 '15 at 13:38
  • Busybox find does not have -delete, so from a portability point of view this still makes sense. – vog Jul 11 '25 at 06:34
  • You can also add -maxdepth 1, since you are using a recursive rm anyways. Then you can also remove -depth. See: https://askubuntu.com/a/1552741/634251 – vog Jul 11 '25 at 06:35
  • The -xdev option is nice, but mostly ineffective due to the use of rm -R, e.g. find may skip some sub-sub-directory, but the rm -R of the outer sub-directory would still delete it. – vog Jul 11 '25 at 06:43
4

To delete (in terminal) all files and subdirectories except for the base directory named "dontdelete":

rm -rf dontdelete/*
kyleN
  • 1,285
4

You can use find with the -delete flag:

find dontDeleteMe/* -delete

The /* is important as it tells find to search only INSIDE the folder called "dontDeleteMe".

Also ensure that the -delete flag is at the end of the find command.

pomsky
  • 70,797
SaultDon
  • 1,772
  • 4
    This solution doesn't delete any hidden files, unless you enable dotglob. Otherwise, using the -mindepth 1 flag option seems the only way to get it working. – Stefan van den Akker Jul 25 '15 at 15:59
3
rm -rf  directory/{.*,/*}

What says:

Remove all files starting with . in "directory" and all other files too.

Though as kindly noted by Neftas this solution is not safe!

Safer solution is:

 rm -rf directory/!(.|..)
Tebe
  • 271
2

There is an even simpler answer:

  1. cd dontDeleteMe

  2. rm -rf *

Basic system administration lecture time: Be sure to pay attention to where you are when you use sweeping commands like this.

I can't say that enough. I've had to recover a box because someone wasn't paying attention and typed in rm -rf * while in /.

*nix assumes that if you are root or if you are sudo-ing as root that you know what you are doing. So make sure that you know what you're doing before you do it.

An alternative which makes sure your 'cd' command works before you issue the 'rm' is to use

cd dontDeleteMe && rm -rf *
grooveplex
  • 2,506
user30619
  • 31
  • 1
  • 6
    This is a dangerous suggestion. What you want is: cd dontDeleteMe && rm -rf * – Izkata Oct 26 '11 at 20:32
  • 1
    @Izkata Or make sure to check that the cd operation was successful, before issuing the rm command. – Eliah Kagan Nov 01 '11 at 17:42
  • 1
    @EliahKagan That's exactly what my code snippet does... – Izkata Nov 01 '11 at 18:00
  • 1
    Actually it's not any more or any less dangerous than what you suggest. All the && does is to chain the two commands together so that they execute at the same time. If anything my method is actually SAFER since you have to stop and .look before you execute the rm -rf *. Pausing to double check is always better. – user30619 Nov 04 '11 at 13:57
  • 6
    @user30619 The && operator doesn't just chain the commands together; it requires that each command be successful before the next one will be executed. If the cd command fails for any reason (directory doesn't exist, privileges, etc) then the rm command won't be executed. I'd call that safer. – ean5533 Nov 09 '11 at 19:14
  • This command is not safe against filenames starting with a -! See also: https://askubuntu.com/a/1552741/634251 – vog Jul 11 '25 at 06:13
1

I am not sure why this is so complex, help me if i am wrong

cd DoNotDeleteDir #<- this is just to make sure we are inside
find . | xargs rm -rf

That's it

  • This has the slight flaw of trying to delete the current directory as well, which, of course, doesn't work, because it's still in use as the working directory of the invoking shell. – David Foerster Sep 15 '15 at 13:26
  • One can delete the current directory from inside it--and then be "in" a nonexistent directory. rmdir ../tmp, from an empty directory called tmp, will do that. The technique in this answer doesn't delete the current directory because the rm command special-cases the specific pathnames . and .., refusing to operate on them. Thus rm: refusing to remove '.' or '..' directory: skipping '.' (from GNU rm, which provides /bin/rm in Ubuntu) is quite literally what is happening. rmdir . behaves similarly, though it shows a less illuminating Invalid argument error. @DavidFoerster – Eliah Kagan Jun 02 '20 at 02:24
0

I would use find as suggested by guciek's answer, and add -xdev to make sure it doesn't descend into other filesystems:

find 'dontDeleteMe' -xdev -mindepth 1 -deletea

(I added quotes in case the real path contains spaces)

An alternative with Bash and rm could be

rm -rf 'dontDeleteMe'/{*,.[!.]*}

This would also remove hidden files, without producing errors. See this answer for details.

mivk
  • 5,821
0

If you need portability with slightly older busybox versions, whose find doesn't have -delete, the most efficient and secure solution I could find is:

find dontDeleteMe/ -mindepth 1 -maxdepth 1 -exec rm -rfv -- '{}' +

Or, for less verbose output the doesn't report every deleted file and directory:

find dontDeleteMe/ -mindepth 1 -maxdepth 1 -exec rm -rf -- '{}' +

Security advice: Better over-use than under-use the -- argument! This protects against path names starting with a - character, which would otherwise be misinterpreted as additional rm flags.

(Admittedly, in this specific find invocation it is hard to trigger that case, given that all arguments to rm are prefixed by dontDeleteMe/, and even if that came from a variable and started with -, it would likely have confused find rather than being passed to rm. But the mere fact that you need these complex kind of reasoning for security should be already a red flag to you. It is wiser to just stick to -- and be done with it.)

Another important detail: Note that the trailing slash of dontDeleteMe/ is optional if dontDeleteMe is a plain directory, but mandatory if dontDeleteMe is a symlink to the actual directory. I recommend to just keep the trailing / to ensure it works as expected in all present and future situations.

How this whole command works: By setting -mindepth as well as -maxdepth to 1, this steps only through the direct files and subdirectories, letting the -r option of rm take care of the actual recursion in the deletion. The + operator of find collects multiple arguments for the rm to provide a minimum total number of rm invocations (in most cases, just one invocation), similar to what xargs does.

vog
  • 127
  • Busybox find does have -delete: "-delete Delete files, turns on -depth option", though oddly it's not enabled on Ubuntu's busybox. But then again, on Ubuntu there's no reason to use busybox find when GNU find is present by default. – muru Jul 11 '25 at 06:43
  • @muru Thanks! I improved my answer to clarify that this is about portability with older busybox versions. – vog Jul 11 '25 at 07:44
-1
rm -rf ${PWD}/*

will clear the present working directory

  • Depending on your shell settings, this will usually not delete the hidden files (starting with a dot). – vog Jul 11 '25 at 06:04
  • Moreover, this is not safe against filenames starting with a -! See also: https://askubuntu.com/a/1552741/634251 – vog Jul 11 '25 at 06:12
-1
  1. Easiest thing for me - a windows expert but an ubuntu newbie
  2. Click the Files icon on the launcher
  3. Navigate to the directory where the files and folders are located that you want to delete
  4. Right Click in a blank area of the window next to the files and click "Open in Terminal" - leave the Files window open
  5. A terminal window will open and will be "set" to the folder you located
  6. You can type "dir" (disregard quotes when i say type) and press enter for the terminal to show a list of files and folders - just to prove you are "in" the right folder
  7. type "rm -rf *" and press enter
  8. depending on size of folders/files to delete system will pause
  9. When terminal prompt returns, the Files window you had opened will now say "Folder is Empty"
  10. I had success with this method and it gave me comfort to see the files/folder both in the Files window and as a result of the Dir command in the terminal window
  11. I was also comforted that the Files window displayed the folder now empty - especially since I had been chasing these files around looking for the trash folder that they were in
  12. Thanks to everyone else who submitted answers - it was very informative
  • 1
    That seems quite convoluted – especially since you're going to end up running rm -rf * anyway. – David Foerster Nov 09 '16 at 00:46
  • Depending on your shell settings, this will usually not delete the hidden files (starting with a dot). – vog Jul 11 '25 at 06:04
  • Moreover, this is not safe against filenames starting with a -! See also: https://askubuntu.com/a/1552741/634251 – vog Jul 11 '25 at 06:12