7 Answers
No, if you did not tweak your shell a lot this will not remove files or directories starting with a .
. To remove them, too, you can either list them explicitly
rm -rf .file .dir
or use the right glob patterns (thanks Chris)
rm -rf .[^.]* ..?*
EDIT The point here is that you cannot use .*
to match files like .file
, because .*
or .*?
will also match ..
or .
. .[^.]*
matches files like .file
, while ..?*
matches files like ..foo
(*
matches zero or more characters while ?
matches exactly one).
8
If you want to remove a directory and all its contents, you can chdir
into the parent directory and them rm -rf
that directory by name, bypassing the entire globbing question. If you want to remove the contents but keep the directory, it’s easiest to remove all and then recreate the directory.
It is complex to come up with a glob that will match all possible directory entries save . and ..; it’s easy to come up with a simple answer (e.g., * .??*
) that will work almost always in practice. This is OK for interactive use, since it’s easy to remember and the times it doesn’t work can be caught with a post-rm ls -a
. For a script, it’s easier to do the remove all and recreate the empty directory.
2
Since I think this question is more about what * does (and not rm), let’s try another approach.
If you are unsure what the * does, you can “test” first using a harmless command like echo.
Before you run this, try to guess what they will show if you run them in your home dir.
echo *
echo .*
But first let’s create a playground so we can play with the stars and see what we end up with.
mkdir ~/star_test/
cd ~/star_test/
>.file1
>file2
Now in this dir we have this:
[email protected]:~/star_test$ ls -1a
.
..
.file1
file2
Now notice what the * expands into using the echo command:
[email protected]:~/star_test$ echo *
file2
[email protected]:~/star_test$ echo .*
. .. .file1
So let’s see what happens with the rm command
[email protected]:~/star_test$ rm -rf *
[email protected]:~/star_test$ ls -1a
.
..
.file1
As you see he did only remove the file2, since * only expanded to file2.
If you would type rm -rf .* that would be the same as writing
rm -rf . .. .file1
And to be honest, that do not look fun 😉
Hope this clarifies the * part of your question.
Update:
However as Ankur Goel points out there is some kind of protection built into rm (kind of unusual for shell commands 🙂
Let’s create a new playground:
cd ~/star_test/
mkdir -p test1/test2/test3
sudo chown root.root test1
cd test1/test2/test3/
>.file1
>file2
So now we have this again, but with test1 owned by root as protection if
rm start to go berserk.
[email protected]:~/star_test/test1/test2/test3$ ls -a
. .. file2 .file1
[email protected]:~/star_test/test1/test2/test3$ echo .*
. .. .file1
So let’s remove everything:
[email protected]:~/star_test/test1/test2/test3$ rm -rf .*
rm: cannot remove directory `.'
rm: cannot remove directory `..'
[email protected]:~/star_test/test1/test2/test3$ ls -a
. .. file2
And it looks like rm did not remove . and .. even if we told him to!!!
So after this long answer it turns out to be safe to remove everything in a dir with this:
rm -rf * .*
But I would use this with care, since I’m not sure all implementations of rm behaves like this!
Yes. rm -rf will only delete files and folders in the current directory, and will not ascend up the file tree. rm will also not follow symlinks and delete the files they point to, so you don’t accidentally prune other parts of your filesystem.
1
A much easier way to empty an entire folder, also avoiding the “too many arguments” issues discussed in this answer, is to simply delete and recreate the directory itself. To make sure this works correctly when you are in a symlinked directory, use the following lines:
cd ..
rm -rf $(readlink -f yourdir) #remove the directory, treat the case of a symlink
# by using readlink, to recreate the linked-to directory
mkdir $(readlink -f yourdir) # recreate the directory to have it empty
cd yourdir
(If you uses yourdir
instead of $(readlink -f yourdir)
you’d only replace the link while the original location remains full)
3
If you don’t want to move one level up like mpez0 said and rm -rf
this specific folder, there is a way to work on all directories/files except .
and ..
in the current folder by doing:
rm -rf $(ls -A)
Of course, if any of the directories/files contains one of the characters in the shell IFS
special variable (e.g. space, tab, newline), you might want to change the IFS first, run the command, then restore IFS.
There is a hidden problem when using *
in Unix shell:
When you have file names start with a dash (-
), these file names could be mistakenly interpreted as options by the programs, such as rm(1).
In this case, for example, if you have a file named -f
in working directory, this file won’t be removed by rm -rf *
, as it will be treated as another -f
option by rm(1); or having a file named -i
would negating the effect of your early specified -f
.
GNU operating systems are more likely to be affected by this issue, because its getopt(3) functions won’t stop at first non-option argument, when looking for options; as a result, even you put *
after some non-options, on a GNU system (or using GNU rm since it has their own getopt(3) implementation that behaves very similar to the one in GLIBC), strangely-named files may still be interpreted as options.
Based on Benjamin Bannier’s answer, to really remove all files in working directory, put a --
before file names, like
rm -rf -- .[^.]* ..?* *
Further reading:
UNIX-HATERS Handbook, section 2, Welcome, User!, Consistently Inconsistent.
22