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.
9 Comments
attrib -r -a -s -h “d:\temp\Root Folder\*.*”
del “d:\temp\Root Folder\*.*” /s /q
Nuts. Repost with the subdirectory parameter for the attrib command:
attrib -r -a -s -h \"d:\\temp\\Root Folder\\*.*\" /s
del \"d:\\temp\\Root Folder\\*.*\" /s /q
The idea here being that you\’re trying to delete the files, not remove the directories, so use a file deletion.
Hi Andrew,
thanks for your comment.
If I understand your script correctly, it only deletes the files (recursively). The attrib line would not really be necessary since del cannot delete directories. Anyway, I am trying to delete everything below a given root folder.
Too right, Helge. In my eagerness to post, I misread the challenge; I thought you were trying to leave the skeleton of the subdirectory tree, by removing all the files. Thus, I suggested using attrib to remove special attributes that might block the deletion, and then use the del command, each with the /s parameter to let them cycle through the subdirectories.
I like to change to the directory itself and then call the rd command. And I see that you ruled out that first simple solution because it doesn\\\’t work with UNC paths.
I suggest using the PUSHD and POPD commands to handle the directory navigation. With Vista, pushd will change directory to a UNC by dynamically creating a drive mapping. I can\\\’t remember if XP can do this as well. Pseudobatch follows:
pushd “%target%”
if not errorlevel 1 (rd /s /q . && popd)
By checking the errorlevel, a mistake in the path or a failure to change to that folder won\\\’t cause an accidental recursive delete!
Hi Andrew,
this is a very interesting solution! Thanks for posting it.
[I have cleaned up the HTML code in your comment a little bit]
Hi @ all,
this is a very nice information. I will create a new script with this information, but I have a question.
I have the following folder systems:
\\dfs\dfs-pfad\Ordner\_allgemein
\\dfs\dfs-pfad\Ordner\_all_germany
\\dfs\dfs-pfad\Ordner\Ordner1
\\dfs\dfs-pfad\Ordner\Ordner2
\\dfs\dfs-pfad\Ordner\Ordner3
Now i will delete all folders inclusive subfolders and files exclude the both fist with the _.
Can somebody help me ?
best regards
Daniel
Appreciated way of devoloping the solution of the problem.
A small comment if I am not mistaken:
%i should be %%i in batch files.
It isn’t one line, but would the following approach be another solution?
robocopy “C:\Temp\Root Folder” “C:\Temp\Root Folder\Delete” /E /CREATE /MOVE /MINAGE:0 /R:10
rd “C:\Temp\Root Folder\Delete” /q /s
Interesting approach ;-)