0

On Mac OS X terminal, how can we remove all files and folders, including hidden ones, recursively, except one directory?

Thank you.

2 Answers 2

3

WARNING: running any command to recursively delete files is dangerous. Always, always test before blindly running such dangerous commands, and never run them as the root user (or with sudo etc.), ever.

This is relatively easy to do with a bit of bash, you could even make it an argument you pass in if you are going to do this a lot. But, for a once off, try something like my simple test below.

First, I will create some folders for testing:

cd test; mkdir -p one two three four five six .hidden

Then, I will create a bash script (in this case rm.bash) with the following content:

for i in `ls -A`
do      
        if [ ! "${i}" == 'three' ] && [ ! "${i}" == $0 ]; then 
                echo "would delete ${i}" 
        else    
                echo "not deleting ${i}" 
        fi
done

To explain: ls -A will print all files except the current folder and the parent (. and ..). We use this list with a for loop to iterate through all the contents. I have decided (arbitrarily) that the only folder we will leave is "three" and that I don't want to delete the rm.bash script itself.

Hence, the if condition will only be true as long as the file/folder in question is not named either three or rm.bash ($0 means this works no matter what you call the file).

Rather than running this immediately with rm -rf ${i} (which is dangerous), I have instead used a couple of echo commands to show what will be deleted and what will not.

Here was my sample output:

would delete five
would delete four
would delete one
not deleting rm.bash
would delete six
not deleting three
would delete two

Once you have verified that the script is taking the correct action, not deleting things that it should not etc., then you can change the code to this:

for i in `ls -A`
do      
        if [ ! "${i}" == 'three' ] && [ ! "${i}" == $0 ]; then 
                rm -rf ${i} 
        fi
done
1

An alternative. Same caveats apply as @Adam C's answer; don't run this without testing it.

Some demo data:

$ mkdir testing; cd testing
$ mkdir one two three four "fi ve"
$ touch one/one.txt two/two.txt three four/keep.txt fi\ ve/.hidden

Simulate deleting all but four/

$ find . -mindepth 1  -path ./four -prune -o -exec echo would remove "{}" +

Output:

would remove ./fi ve ./fi ve/.hidden ./two ./two/two.txt ./one ./one/one.txt ./three

Notes:

-mindepth 1  prevents including /.
Prune removes path four/ from processing, or...
-o means "or" (either prune the left, or exec on the right)
High speed / low resource use:
  find will stop processing a tree once pruned (no wasted operations)
  One xargs-style list is built (with +), removal happens in one command.
  To process one at a time, replace + with \;
Spaces are handled correctly within " "
-delete is shorter but may not operate on directories
find won't follow symlinks by default

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .