Puzzle: Delete Directory Content Without Deleting the Directory Itself (on the Command Line)
The Windows command line is a powerful beast. It can be made to do things one would never have thought possible, but it can be very tricky indeed to find out just how to make it jump through a particular hoop.
Here is a real problem I had to solve for those who like puzzles:
How to delete the entire content of a directory without deleting the directory itself?
The following restrictions must be met by a solution to qualify:
- It must work with relative, absolute, local and UNC paths.
- It must delete read-only, hidden and system files and directories, in addition to those objects without special attributes.
- It must use only commands that are available in the OS (in my case Windows XP or newer).
At first, this may seem simple: the command processor has a built-in command for removing directories, rd. But unfortunately rd does not have an option for removing the directory content only. So we have to create our own solution.
After thinking about the problem for some time I decided to search the internet. This is the first approach I found:
rd /s /q "d:\temp\Root Folder" md "d:\temp\Root Folder"
Deleting the directory itself with rd and then recreating it with md is out of the question: that way, security descriptors are lost (and one might not even have the permission to recreate the directory).
Here is another find from the net:
cd /d "d:\temp\Root Folder" rd /s /q "..\Root Folder"
Changing into the directory with cd and deleting it with rd /s /q “..\directory to delete” does not work either: the command processor does not support cd’ing into a remote (UNC) path. It would work with local paths, though: the current working directory of cmd.exe cannot be deleted.
Next I started playing around on my own:
for /f "delims=" %i in ('dir /a /b /s "d:\temp\Root Folder"') do @echo %i
This recursively lists all files and folders inside the root folder (regardless of attributes), but there is no command I know of that deletes both single files and directories. Besides, one would have to start at the deepest level with folder deletion, but this command begins with the highest level.
So it looks like it is necessary to delete files and folders separately. Let us start with files:
del /a /f /q "d:\temp\Root Folder\*"
This deals with all files (regardless of attributes) at the first level. But how to delete the folders? What we need is a way to list all folders on the first level so we can delete them with rd /s.
Let us try a simple for /d loop:
for /d %i in ("d:\temp\Root Folder\*") do @echo %i
This does not work because folders with the hidden or system attributes are ignored.
What about a for /f loop:
for /f "delims=" %i in ('dir /ad /b /s "d:\temp\Root Folder"') do @echo %i
This is nice. It lists all folders (including those with hidden or system attributes), but we only need the folders at the first level. If we omit the switch /s, we do not get the full path to each folder. But we can work from there:
for /f "delims=" %i in ('dir /ad /b "d:\temp\Root Folder"') do @echo "d:\temp\RootFolder\%i"
That is what we need. All folders on the first level.
Putting it all together, we get the following two liner:
del /a /f /q "d:\temp\Root Folder\*" for /f "delims=" %i in ('dir /ad /b "d:\temp\Root Folder"') do @rd /q /s "d:\temp\Root Folder\%i"
If you want to look for an easier solution, you can use the following batch file to generate some test data. If you manage to squeeze this into a one-liner, please let me know by dropping a comment.
Create test files and folders:
@echo off md "Root Folder\Sub Folder 1\Sub Folder 1_2" md "Root Folder\Sub Folder 2\Sub Folder 2_2" echo File1>"Root Folder\File 1.txt" echo File2>"Root Folder\File 2.txt" echo File2>"Root Folder\File 3.txt" echo File3>"Root Folder\Sub Folder 1\File 1_1.txt" echo File3>"Root Folder\Sub Folder 2\File 2_1.txt" attrib "Root Folder\File 1.txt" +r attrib "Root Folder\File 2.txt" +s attrib "Root Folder\File 3.txt" +h attrib "Root Folder\Sub Folder 1" +r +s +h
Note: if you want to use “for” loops from a batch file, you have to double the percent signs in front of the variable i.