3

We have a folder structure like this

dir 1
  - dir A
  - dir B
dir 2
  - dir C
dir 3
dir 4

Need to move to other directory, all dirs and subdirs, to same level, like this

d:\basedir
    dir 1
    dir A
    dir B
    dir 2
    dir C
    dir 3
...

I¡ve tried this script but, doesn't works

 for %%x in (%*) do (
    move %%x d:\basedir\
)
Squashman
  • 13,649
  • 5
  • 27
  • 36
cugel
  • 33
  • 3

3 Answers3

3

The difficulty with the standard methods to solve this type of problems is that they works top-to-bottom, that is, they process first the top-most level folder. To correctly solve this problem the folders must be processed bottom-to-top: process first the last folders in the tree.

You may use the recursive process of a directory tree described at this answer

@echo off
cd D:\data\folder
call :treeProcess
goto :eof

:treeProcess
for /D %%d in (*) do (
   cd "%%d"
   call :treeProcess
   cd ..
   move "%%d" D:\basedir
)
exit /b

Or, in a simpler way:

@echo off
cd D:\data\folder

:treeProcess
for /D %%d in (*) do (
   cd "%%d"
   call :treeProcess
   cd ..
   move "%%d" D:\basedir
)
Aacini
  • 65,180
  • 12
  • 72
  • 108
3

When you move a directory, its sub-directories are no longer available at the source location, so you need to first handle sub-directories before you move their parents:

rem /* Iterate through all directories in the tree, and change the default
rem    top-to-bottom order to bottom-to-top order per each sub-branch: */
for /F "delims= eol=|" %%I in ('
    dir /S /B /A:D-H-S "D:\source\*" ^| sort /R
') do (
    move "%%~I" "D:\basedir\"
)

If you just want the sub- and sub-sub-directories to be moved but not deeper ones, use this code instead:

rem // Iterate through immediate child directories:
for /D %%J in ("D:\source\*") do (
    rem // Iterate through grandchild directories:
    for /D %%I in ("%%~J\*") do (
        rem // Move current grandchild directory:
        move "%%~I" "D:\basedir\"
    )
    rem // Move current child directory:
    move "%%~J" "D:\basedir\"
)
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Although `dir /S /B /A:D` command gives the folders in "natural" top-down order, sorting this list via `sort /R` command does _NOT_ order the list in "its reverse order", but in _alphabeticall_ reverse order. You may store the list in an array: `for /F "delims=" %%a in ('dir /S /B /A:D') do set /A "n+=1" & set "folder[!n!]=%%a"` and then process the array in reverse order: `for /L %%i in (%n%,-1,1) do move "!folder[%%i]!" "D:\basedir\"` – Aacini Jan 27 '22 at 23:50
  • @Aacini, I agree, my wording was not correct, but the key is bottom-to-top, even though the paths become resorted by reverse alphabetical order; so this approach should work perfectly fine whatsoever, because `a\b\c` comes before `a\b` which comes before `a`, with `sort /R`… – aschipfl Jan 28 '22 at 10:23
  • 1
    You are right: although the order of _the whole list_ is not the reversed of the original list, inside _each subfolder tree_ the names comes in bottom-to-top order. +1 – Aacini Jan 28 '22 at 12:54
-2

FOR /D should do what you need.

Consider this example:

SET "SOURCE_DIR=n:\path\to\data"
FOR /D %%d IN (%SOURCE_DIR%\*.*) DO (
    @ECHO %%~fd
)

It returns the absolute path to all the directories underneath SOURCE_DIR.

Gerhard
  • 22,678
  • 7
  • 27
  • 43
mojo
  • 4,050
  • 17
  • 24
  • 2
    Not work for me. It move the dirs with subdirs included. i need to move each subdir to top level – cugel Jan 27 '22 at 16:29