76

rm -rf /some/path/* deletes all non-hidden files in that dir (and subdirs).

rm -rf /some/path/.* deletes all hidden files in that dir (but not subdirs) and also gives the following error/warning:

rm: cannot remove directory: `/some/dir/.'
rm: cannot remove directory: `/some/dir/..'

What is the proper way to remove all hidden and non-hidden files and folders recursively in a target directory without receiving the warning/error about . and ..?

36

You could always send error messages to /dev/null

rm -rf /some/path/.* 2> /dev/null

You could also just

rm -rf /some/path/
mkdir /some/path/

...then you won't have to bother with hidden files in the first place.

  • 2
    But what if I only want to delete the hidden files? – CMCDragonkai Jun 1 '14 at 13:52
  • @CMCDragonkai that should be a different question, but you can find the solution in Gilles' answer (rm ..?* .[!.]* should do it). – evilsoup Jun 1 '14 at 18:14
  • 14
    Doesn't deleting and recreating the directory pose the risk that the file permissions are not right afterwards (especially important in server environments). Who could one create the folder with the same permissions as before automatically? – Yo Ludke Sep 23 '15 at 8:46
  • @YoLudke You are absolutely correct, in many situations it doesn't matter but deleting the folder and recreating is not semantically equivalent to emptying that folder; so be careful doing that! – Thomas Dec 29 '15 at 5:43
  • Deleting the directory is not always possible. In my case the directory is a docker volume, and while i can do whatever I want inside the volume, i cant change the volume itself from within the container. – dovidweisz Jun 3 at 15:15
82

* matches all non-dot-files, .[!.]* matches all dot files except . and files whose name begins with .., and ..?* matches all dot-dot files except ... Together they match all files other than . and ... If any of these three patterns matches nothing, it expands to itself; rm -f doesn't care about non-existent arguments, so this doesn't matter.

rm -rf ..?* .[!.]* *

You can also use find. This is more complex but has the advantage of working even if there are so many files that the wildcards above would expand beyond your system's command line length limit.

find . -name . -o -prune -exec rm -rf -- {} +

You may find it clearer to remove and recreate the directory. This has the advantage (or downside, as the case may be) of resulting in an empty directory even if another program is concurrently creating files in the original directory.

  • 8
    This should be the accepted answer, as it prevents parent traversal and possible deletion. – rbellamy Jun 12 '15 at 17:06
  • The find alternative returns "success" even if some file is not successfully deleted; not good for script. – Franklin Yu Jul 29 '16 at 7:22
  • With regards to your second find command, the manpage for find states "Because -delete implies -depth, you cannot usefully use -prune and -delete together." -- yet you use -prune -delete? – Doktor J Aug 18 '16 at 21:29
  • @DoktorJ Indeed, -prune doesn't do anything here. And on reading back I see that I didn't answer the question correctly: I took care not to recurse, but the question explicitly asks for recursive deletion. I've corrected my answer. – Gilles Aug 18 '16 at 21:53
  • 1
    @haylem In zsh, you need to write .[^.]* instead of .[!.]* when history substitution is enabled (which by default is the case interactively but not in scripts), because zsh parses ! as a history reference. But in zsh you wouldn't need that in the first place, you can just use *(D) to include dot files (without . or ..) in the wildcard match. – Gilles Aug 1 '17 at 14:29
19

Just realised this is the most convenient way in most Linux distros:

ls -A1 | xargs rm -rf

where

-A = list everything except . and ..

-1 = put every item in one line

  • 4
    downside which I see is: you need to 'cd' into directory to do this. – kumar Nov 24 '16 at 9:38
  • ls -A1 /your/path/ | xargs rm -rf should apply – godzillante Nov 24 '16 at 14:02
  • nope..it does not help - For example: ls -A1 ~/test/ | xargs rm -rf this command deletes files which I am currently 'cd into'..not in the directory ~/test. – kumar Nov 25 '16 at 6:44
  • 4
    It doesn't work if any of the file names contain blanks, newlines, quotes or backslashes. – Stéphane Chazelas Jun 13 '17 at 12:14
  • -1 Because of above comment. ↑↑↑↑↑↑↑↑ – somethingSomething Jul 12 at 20:54
15

Either change the dotglob option of your shell and use *, or use something like find.

find somedir -mindepth 1 -delete
  • 2
    Or you could simply rm -rf /some/dir and then create a new empty directory in its place. – tripleee May 26 '13 at 12:11
  • Best option so far. Very safe since you explicitly specify the directory path. – Yanick Girouard Jul 11 at 20:01
4

This should work just like @Gilles answer but more compact:

rm -rf {,.[!.],..?}*

or

rm -rf dir/to/files/{,.[!.],..?}*

should also add an if for usage in scripts just to be safe:

if [ -d "$DIR" ]; then
    rm -rf ${DIR}/{,.[!.],..?}*
fi
  • 1
    Oddly enough, as a bash alias on Ubuntu 16.04 LTS, the previous answer wasn't working. However, alias cleandir='rm -rf {,.[!.],..?}*' does. – Steven Ventimiglia Apr 14 '18 at 18:44
3

Find is your friend.

find ! -name '.' ! -name '..' -delete

% find ! -name '.' ! -name '..'
./test
./test4
./test4/.test6
./test3
./.test5
./test2
% find ! -name '.' ! -name '..' -delete    
% find ! -name '.' ! -name '..'     
%             

If you wish to use recursively search something other your current directory ($PWD), then add a path right after the find command; e.g., find /path ! -name '.' ! -name '..' -delete. If you only want to descend n number of directories, then use the -maxdepth n option right after the /path parameter.

The above command was tested on an Ubuntu 13.04 system. Will likely work on other, modern linux systems.

  • to delete all directories in the current directory you could do find . ! -name '.' ! -name '..' -type d -delete – Andy Jul 3 '16 at 4:01
1

I suggest you experiment with

Turn-ON dots (hidden files)

  • set dotglob

    shopt -s dotglob

Turn-OFF dots

  • unset dotglob

    shopt -u dotglob

This method worked exactly as I wished for a copy command that was missing the hidden directories.

    shopt -s    dotglob
    cp    -rvn  ./$from/*  ./$too/
    shopt -u    dotglob

So I did a remove (delete), and oops ...

    shopt -s    dotglob
    rm -fr ../message_splitter--044a/*
    shopt -u    dotglob

... that works too!

It occurs to me that you dear reader can't see the message_splitter directory. Any way it has a .svn folder that needs to be removed, and copied Into.

From man page ...

dotglob If set, bash includes filenames beginning with a `.' in the results of pathname expansion.

references:

0

What is the proper way to remove all hidden and non-hidden files and folders recursively in a target directory without receiving the warning/error about . and ..?

Assuming the directory in question is ./dir, then

rm -rf ./dir

would remove all files in ./dir, including hidden files and directories, recursively, and including the ./dir directory itself.

If you do not want to delete the directory itself, then you may just recreate it afterwards, or use

find ./dir -mindepth 1 -delete

or if you find does not support -delete,

find ./dir -mindepth 1 -depth -exec rm -rf {} ';'

Using -mindepth 1 allows you to keep the top-level directory ./dir.

-2

Try this code:

Dirlist=``find /some/path/ -type d -name '.[^.]*'`
for HiddenDir in $Dirlist
do
    rm -rf $HiddenDir
done

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.