0

I want to loop recursively through a directory and have it's filenames echoed. I ran into the 1 vs 01 name trouble. Say, I have this:

D:\Downloads\prefixorder\order\1.txt
D:\Downloads\prefixorder\order\10.txt
D:\Downloads\prefixorder\order\2.txt
D:\Downloads\prefixorder\order\3.txt
D:\Downloads\prefixorder\order\1\new.txt
D:\Downloads\prefixorder\order\10\new.txt
D:\Downloads\prefixorder\order\2\new.txt
D:\Downloads\prefixorder\order\order\1.txt
D:\Downloads\prefixorder\order\order\10.txt
D:\Downloads\prefixorder\order\order\2.txt
D:\Downloads\prefixorder\order\order\20.txt
D:\Downloads\prefixorder\order\order\3.txt
D:\Downloads\prefixorder\order\order2\1.txt
D:\Downloads\prefixorder\order\order2\10.txt
D:\Downloads\prefixorder\order\order2\2.txt
D:\Downloads\prefixorder\order\order2\20.txt
D:\Downloads\prefixorder\order2copy\1.txt
D:\Downloads\prefixorder\order2copy\10.txt
D:\Downloads\prefixorder\order2copy\2.txt
D:\Downloads\prefixorder\order2copy\20.txt
D:\Downloads\prefixorder\order3\1.txt
D:\Downloads\prefixorder\order3\10.txt
D:\Downloads\prefixorder\order3\2.txt
D:\Downloads\prefixorder\order3\20.txt
D:\Downloads\prefixorder\1.txt
D:\Downloads\prefixorder\10.txt
D:\Downloads\prefixorder\2.txt

and I want to have 10 listed below 1 in each folder (and the folder being sorted like this, too).

Basically looking like this:

D:\Downloads\prefixorder\1.txt
D:\Downloads\prefixorder\2.txt
D:\Downloads\prefixorder\10.txt
D:\Downloads\prefixorder\order\1.txt
D:\Downloads\prefixorder\order\2.txt
D:\Downloads\prefixorder\order\3.txt
D:\Downloads\prefixorder\order\10.txt
D:\Downloads\prefixorder\order\1\new.txt
D:\Downloads\prefixorder\order\2\new.txt
D:\Downloads\prefixorder\order\10\new.txt
D:\Downloads\prefixorder\order\order\1.txt
D:\Downloads\prefixorder\order\order\2.txt
D:\Downloads\prefixorder\order\order\3.txt
D:\Downloads\prefixorder\order\order\10.txt
D:\Downloads\prefixorder\order\order\20.txt
D:\Downloads\prefixorder\order\order2\1.txt
D:\Downloads\prefixorder\order\order2\2.txt
D:\Downloads\prefixorder\order\order2\10.txt
D:\Downloads\prefixorder\order\order2\20.txt
D:\Downloads\prefixorder\order2copy\1.txt
D:\Downloads\prefixorder\order2copy\2.txt
D:\Downloads\prefixorder\order2copy\10.txt
D:\Downloads\prefixorder\order2copy\20.txt
D:\Downloads\prefixorder\order3\1.txt
D:\Downloads\prefixorder\order3\2.txt
D:\Downloads\prefixorder\order3\10.txt
D:\Downloads\prefixorder\order3\20.txt

So somewhat the same order as the default any win7 explorer display sorted after ascending alphabet. (Though in that version the files of a root files get to show below the folders, but that doesn't really matter). A nice bonus would be, that this output comes no matter what object I dragged the dropped it from.

I found this, which solves this problem nicely for one folder: Read files in directory in order of filename prefix with batch?

The diffrence to that problem that I want this recursively and while multiple files/folders can be dropped.

My current (buggy) modification looks like this:

@echo off
setlocal EnableDelayedExpansion
rem Create an array with filenames in right order

if [%1]==[] goto :eof
:loop
for /f "tokens=* delims=" %%a in ('dir "%~1"  /a-d  /s /b') do (
   for /F "delims=-" %%i in ("%%a") do (
      set "number=00000%%~ni"
      set "file[!number:~-6!]=%%a"
   )
)
rem Process the filenames in right order
for /F "tokens=2 delims==" %%f in ('set file[') do (
   echo %%f
)

shift
if not [%1]==[] goto loop


@pause

the most buggy line in question would seem to be

set "file[!number:~-6!]=%%a"

whose array parameter in fact I don't even really begin to understand. My guess anyhow is that the array's entries are overwritten in each loop, because the parameters are pretty much the same in each loop.

I had also supected that the %%~ni is probably the cause of the overwriting, since the filenames inside the folders are all the same. Using %%~ni seems to me pbviously wrong, but using %%i simply doesn't do any sorting anymore and echoes out 10 before 1, which is even more wrong. It works however if multiple folders are dragged, since they are in seperate echo loops. I tried putting in the echo loop within the first outer loop before and after the first inner loop. While it does make it that nothing gets omitted, it's not sorting properly at all.

Back to the major question: how do I solve that recursively and with mutiple files/folders dragged, that sorts the filenames and foldernames. foldernames weirdly are of no prolem when recursively in one folder. It become a problem, when multiple folders/files are dragged, since it then starts off with the dragged object as the first argument.

Do I need to use an array of arrays or something like that? (Tried looking into it, didn't really get how that is possible in batch, yet, through.) Or is there any other way to do this?

Community
  • 1
  • 1
kumoyadori
  • 337
  • 2
  • 10
  • 21
  • you don't have "-" in your file names, why are you splitting by dash: for /F "delims=-" %%i in ("%%a") do ( ? – mihai_mandis Jan 28 '14 at 21:07
  • @mihai_mandis Perhaps it's just a way of not splitting the files names. – unclemeat Jan 28 '14 at 22:02
  • There is a free version of what used to be 4dos/4nt and it supports natural sorting - `Take Command`. http://en.wikipedia.org/wiki/Take_Command_%28command_line_interpreter%29 – foxidrive Jan 29 '14 at 07:09
  • @mihai_mandis In fact no particular reason at all, except that I simply copied and pasted the code stub from the link and didn't notice. – kumoyadori Jan 29 '14 at 10:40
  • @foxidrive Thanks, through I would like it to work without the need of installing any other tool if that is possible. – kumoyadori Jan 29 '14 at 10:40
  • So you have a list of paths as input. Sorry, it is not clear to me what the output should be? Please put that in qustion description. – mihai_mandis Jan 29 '14 at 13:15
  • So - could you just show us an example of how you want to see the output, rather than theorising about what's going wrong with your implementation of a sort order you haven't explained? – Magoo Jan 29 '14 at 13:46

1 Answers1

0

Not even sure this is what you need, but just if it can help ...

@echo off

    :: Without arguments, just list current folder

    if "%~1"=="" (
        call :recursiveSortedFileFolderList "%cd%"
        goto :eof
    )

    :: Else, create a list of elements to sort
    set "tempFile=%temp%\%~nx0.tmp"
    call :generateList %* > "%tempFile%"
    call :recursiveSortedFileFolderList "%tempFile%"
    del "%tempFile%" >nul
    goto :eof

:generateList
    echo(%~1
    if not "%~2"=="" shift & goto :generateList
    exit /b

:recursiveSortedFileFolderList startFolder 

    setlocal enableextensions disabledelayedexpansion

    :: Prepare padding base
    set "pad=#################################"
    set "pad=%pad%%pad%"
    set "pad=%pad%%pad%"
    set "pad=%pad%%pad%"

    :: paddings for numeric or alphabetic prefixed files and folders
    set "_NPad=%pad%"
    set "_APad=%pad:#=$%"

    :: start work
    call :_doRecursiveSortedFileFolderList "%~1"

    :: cleanup and exit
    endlocal
    exit /b

:_doRecursiveSortedFileFolderList folder
    :: adjust environment for current folder 
    setlocal
    set "timestamp=%time::=%"
    set "tempFile=%temp%\%~nx0.%random%%random%%random%%random%.%timestamp:,=%.tmp"
    set "folder=%~1" & if not defined folder ( set "folder=." ) else ( set "folder=%~f1" )

    :: determine if we are handling a folder or a file with elements in it
    if exist "%folder%\" (
        set "cmd=dir /b ""%folder%\*"" 2^>nul"
    ) else if exist "%folder%" (
        set "cmd=more ""%folder%"" "
        set "folder="
        for /f "tokens=* usebackq" %%a in ("%folder%") do if not defined folder (
            for /f "tokens=*" %%b in ("%%~dpa\.") do set "folder=%%~dpnxb"
        )
    ) else (
        endlocal
        exit /b
    )

    :: For each element in the indicated folder/file, prefix it with the adequated prefix 
    :: depending if it is a file or a folder, and send the output to a temporary file 
    :: that will be sorted (using the adecuate prefix), and processed
    (for /f "tokens=*" %%a in ('%cmd%') do (

        :: determine if file or folder
        if exist "%folder%\%%~nxa\" ( set "type=f" ) else  ( set "type=a" )

        :: determine correct padding
        if "%%~na" geq "a" ( set "name=%_APad%:%%~na" ) else ( set "name=%_NPad%:%%~na" )

        :: generate final padded record
        setlocal enabledelayedexpansion
        echo(!type!:!name:~-260!%%~xa
        endlocal
    ))> "%tempfile%"

    :: Sort the temporary file and for each element on it, if it is a file, echo to console, 
    :: else it is a folder and a recursive call is made to process it
    for /f "tokens=1,2,* delims=:" %%a in ('sort /L "C" "%tempfile%"') do (
        if "%%a"=="a" (echo(%folder%\%%c) else (call %0 "%folder%\%%c")
    )

    :: clean and exit
    endlocal & del "%tempfile%" > nul 2>nul
    exit /b
MC ND
  • 69,615
  • 8
  • 84
  • 126
  • This looks very much like what I am looking for. Thanks! – kumoyadori Jan 29 '14 at 15:06
  • If I may ask for some more help; I tried to modify your code example to write the output into a file (which worked) and then for unicode support in UTF8 with BOM file, but that to no avail so far. Somehow chcp 65001 wouldn't want to work. Creating a BOM before using these call functions made it get stuck while being called. I am a bit at a loss. – kumoyadori Jan 29 '14 at 17:36
  • @kumoyadori, See [here](http://stackoverflow.com/a/19726105/2861476) for the same problem/solution – MC ND Jan 29 '14 at 19:57
  • I know that (the question was from me back then too), thanks again for that solution. But I seem to have rather some trouble to fuse these two together. It just gets stuck and does nothing halfway. My guess ist, that it's probably about the enable/disabledelayedexpansion, but not sure, since the idea didn't help fixing it... – kumoyadori Jan 29 '14 at 22:22
  • @kumoyadori, sorry, i didn't remember it was you. How to solve (i hope): put into this batch the BOM generation from linked answer. generateBOM in finalFile.txt, change pagecode to 65001, use `call :recursiveSortedFileFolderList ...... >> finalFile.txt` (where it is called for current directory or arguments). Include the `
    ` tag (if needed) after the `echo(%folder%\%%c` (the only output line). Done.
    – MC ND Jan 30 '14 at 06:52