I have a large volume of files organized in a very hierarchical folder structure. In this structure, the file that I care about is always located in the lowest level of the folders. As such, I'd like to flatten the directory so that it's easier to access the files that I care about. However, I'd like to preserve the 2 higher levels (Person & Project) of the folder structure.
Here's an example of the EXISTING folder directory:
- Directory
- Tom
- Project 1
- Subfolder Level A
- FileA
- FileB
- Subfolder Level A
- Project 2
- Subfolder Level C
- FileC
- FileD
- Subfolder Level C
- Project 1
- Jerry
- Project 1
- Subfolder Level E
- FileE
- Subfolder Level E
- Project 1
- Tom
Here's an example of the DESIRED folder directory:
- Directory
- Tom
- Project 1
- FileA
- FileB
- Project 2
- FileC
- FileD
- Project 1
- Jerry
- Project 1
- FileE
- Project 1
- Tom
I have tried doing something like this, however this flattens all of the files into a single directory:
for /r %f in (*) do @copy "%f" .
However, this produces:
- Directory
- FileA
- FileB
- FileC
- FileD
- FileE
I'd appreciate any guidance that you can offer. Thanks a lot!
4 Answers
Here is a Powershell approach. It gets a list of the folders at the level that you want. Then it moves all the sub files up to that level. it will also remove the sub folders.
$Rootfolder = Dir directory\*\* -Directory
ForEach($folder in $Rootfolder)
{ Dir $folder.fullname -Recurse -File | Copy-Item -Destination $folder.fullname Dir $folder.fullname -Recurse -Directory | Remove-Item -Force -Recurse -WhatIf
}If you want it to delete, remove the -WhatIf from the last line.
Throw a couple of extra for loops around the one that works then.
e.g. First change to the name folder, then the project folder, looping through both levels.
for /D %n in (*) do ( pushd %n for /D %p in (*) do ( pushd %p for /r %f in (*) do @copy "%f" . popd ) popd
)If you put this in a bat file, remember to replace % with %%
7@echo off
pushd yourDirectory
for /d %%A in (*) do for /d %%B in ("%%A\*") do for /d %%C in ("%%B\*") do ( pushd "%%C" for /r %%F in (*) do move /y "%%F" "%%B" >nul popd rd /q /s "%%C"
)
popd%%A contains something like "yourDirectory\Tom"
%%B contains something like "yourDirectory\Tom\Project 1"
%%C contains something like "yourDirectory\Tom\Project 1\subdirectory1"
%%F contains a file to move, to any depth
At first I thought I could eliminate PUSHD/POPD and use
for /r "%%C" %%F in (*) do ... THIS DOES NOT WORKBut that doesn't work - the value after /R cannot use a FOR variable or delayed expansion because of how the command is parsed.
I tweaked @ScottC's answer and used the following code:
for /D %%n in (*) do ( pushd %%n for /D %%p in (*) do ( pushd %%p for /r %%f in (*.ppt) do ( move "%%f" "[ROOT_PATH_THAT_I_WANT]\%%n\%%p". ) popd ) popd
)I ran this solution as a .bat file, which is why I used %% instead of %.
%%n = name (aka C:\Directory\Name)
%%p = project (aka C:\Directory\Name\Project)
%%f = file to be moved (recursively drilling through the folders and moving them up to the project level)
Ultimately, I wasn't able to get @dbenham's suggestion of deleting the empty folders to work, so I ended up using this utility: . So far it seems pretty intuitive and like it's taking care of the problem without much effort from me :)
Thanks for the help everybody!