I have multiple folders s1,s2.....sn on main directory. Each of these folders have multiple sub folders, folders within folders and then files. Structure kind of looks like:
mainDir
-s1
-f1
-c1
-a.txt
-b.txt
-c2
-m.txt
-n.txt
-f2
-c1
-aaa.txt
-bbb.txt
-c2
-mmm.txt
-nnn.txt
-s2
-f1
-c1
-a.txt
-b.txt
-c2
-m.txt
-n.txt
-f2
-c1
-aaa.txt
-bbb.txt
-c2
-mmm.txt
-nnn.txt
-s3 ..................
Now we need to get rid of all subfolders and keep only . the first level folders and all the underlying files. So final destination should like:
DestDirectory
-s1
-a.txt
-b.txt
-m.txt
-n.txt
-aaa.txt
-bbb.txt
.....so on
-s2
-a.txt
-b.txt
-m.txt
-n.txt
-aaa.txt
-bbb.txt
.....so on
I would use a for /D
loop to iterate the first-level sub-directories, then a nested for /R
loop to iterate through all files in the immediate sub-directories, then use copy
to copy each file individually in order to achieve the flat destination directory hierarchy. To avoid file name collisions (meaning that files with the same name appear in different source sub-directory hierarchy levels), an if exist
directive can be used. So here is the code:
rem // Loop through immediate sub-sirectories of main directory:
for /D %%I in ("D:\MainDir\*") do (
rem // Temporarily change to the currently iterated sub-directory:
pushd "%%~I" && (
rem // Iterate through all files in the current directory recusrively:
for /R %%J in ("*.*") do (
rem /* Create destination directory if necessary, which is named like
rem the current directory, that is the first source sub-directory: */
2> nul md "D:\CopyDir\%%~nxI"
rem // Temporarily change to the destination directory:
pushd "D:\CopyDir\%%~nxI" && (
rem // Check for potential file name collisions:
if not exist "%%~nxJ" (
rem // No collision, hence copy current file:
copy "%%~J" "%%~nxJ"
) else (
rem // Collision, so return an error message:
>&2 echo ERROR: "%%~nxI\%%~nxJ" already exists!
)
rem // Return from destination directory:
popd
)
)
rem // Return from currently iterated source sub-directory:
popd
)
)
The first thing you need to do is to find out if there would be any filename collisions occur when moving files from multiple directories into a single directory.
=== Find-DupeFilenames.ps1
$h = @{}
Get-ChildItem -File -Recurse |
ForEach-Object {
if ($h.ContainsKey($_.Name)) {
"Name conflict {0} is in both {1} and {2}" -f @($_.Name, $h[$_.Name], $_.DirectoryName)
} else {
$h.Add($_.Name, $_.DirectoryName)
}
}
If you need to run this from a cmd.exe shell prompt, use this to get a quick count.
CD /D C:\mainDir
powershell -NoLogo -NoProfile -Command "(C:\src\Find-DupeFilenames.ps1 | Measure-Object).Count"
Use this to list all conflicted filenames.
CD /D C:\mainDir
powershell -NoLogo -NoProfile -Command ".\Find-DupeFilenames.bat"
How is this any different from your Previous question? How to copy files from sub folder only using cmd?
Perhaps in your previous Q you had all same-named folders?
The Code below should also work for the differently named folders as you described here.
CMD Script:
@(SETLOCAL
ECHO OFF
SET "_MainDir=C:\Main\Dir"
SET "_DestDir=%Temp%\Destination\Main\Dir"
)
FOR /D %%A in (
%_MainDir%\*
) DO (
IF NOT EXIST "%_DestDir%\%%~nxA" MD "%_DestDir%\%%~nxA"
FOR /F %%a IN ('
DIR /A-D /S /B "%%~fA\*"
') DO (
ECHO Copying: "%%~fa"
ECHO To: "%_DestDir%\%%~nxA\%%~nxa"
COPY /B /V /Y "%%~fa" "%_DestDir%\%%~nxA\%%~nxa"
)
)