1

I would like to sort a set of files in a specific order using a batch file. The files should be grouped by Floor number and sorted by a string which is contained in the filename.

An example of some file names are as follows:

Floor_1_SomeName_PCI_Some Trailing Text.JPG
Floor_1_SomeName_RSRP_Some Trailing Text.JPG
Floor_1_SomeName_RSRQ_Some Trailing Text.JPG
Floor_1_SomeName_RSSI_Some Trailing Text.JPG
Floor_1_SomeName_SINR_Some Trailing Text.JPG
Floor_1_SomeName_TX Power_Some Trailing Text.JPG

Floor_2_SomeName_PCI_Some Trailing Text.JPG
Floor_2_SomeName_RSRP_Some Trailing Text.JPG
Floor_2_SomeName_RSRQ_Some Trailing Text.JPG
Floor_2_SomeName_RSSI_Some Trailing Text.JPG
Floor_2_SomeName_SINR_Some Trailing Text.JPG
Floor_2_SomeName_TX Power_Some Trailing Text.JPG

I would like to sort all files by its Floor number first, then by the following order:

RSSI
RSRP
RSRQ
SINR
TX Power
PCI

Is there a way I can utilize the sort command to organize this?

aschipfl
  • 33,626
  • 12
  • 54
  • 99
James Hayek
  • 643
  • 3
  • 10
  • 35
  • 1
    No. Sort won't let you set up arbitrary, illogical ordering. Neither will dir or any of the other Windows commands. You can see what is possible using sort by typing `sort /?` at a command prompt (the same is true for `dir /?`). What are you trying to sort for? A directory listing? Where are you trying to display the sorted list? – Ken White Jan 11 '17 at 18:22
  • Maybe I can write a batch file to look for each keyword, RSSI ... PCI and append a numerical value (01, 02...) prior to that name. This should sort everything in the order I need. I was trying to sort the list of files in that specific order because when I convert all these JPGs to a single multi-file PDF, it would be in the order I need it in after converting to the PDF format. @KenWhite – James Hayek Jan 11 '17 at 18:51
  • 1
    So can't you put the filenames in a text file, sort it however you want in that text file, and then process that text file using `for /f` to feed your converter the files in the proper order? – Ken White Jan 11 '17 at 18:54
  • @KenWhite That sounds like an excellent idea. But I am still unsure of a few steps. What I do know is how to create that list: dir /B /ON > FileList.txt which will write a file named FileList.txt, sOrting alphabetically using Bare format. What I don't know is how to sort in the text file for the above parameters. – James Hayek Jan 11 '17 at 19:25
  • Could the `SomeName` part also contain `_` characters on its own? Is the `Floor` number always a one-digit number? – aschipfl Jan 12 '17 at 18:12

3 Answers3

3
@echo off
    setlocal enableextensions disabledelayedexpansion

    rem Retrieve folder from command line. By default current folder
    for %%a in ("%~f1.") do set "folder=%%~fa"

    rem Configure the order of the files
    set /a "RSSI=1", "RSRP=2", "RSRQ=3", "SINR=4", "Tx=5", "PCI=6"

    rem %%f - For each file in the indicated folder
    rem     %%a %%b %%c - Separate the elements of the file name
    rem     Use the elements to generate a serial number for the file
    rem     Output the serial number and the file name
    rem Pipe the generated list into sort to sort on serial number
    rem %%d Retrieve the sorted list 
    rem     separate serial number and file name
    rem     output file name

    (
        for %%f in ("%folder%\Floor*") do @(
            for /f "tokens=2,4 delims=_" %%a in ("%%~nxf") do @for /f %%c in ("%%b") do @(
                set /a 10000000+%%a*100000+%%c
                echo( %%~nxf
            )
        )
    ) | sort | for /f "tokens=1,*" %%d in ('findstr "^"') do @echo(%%e

Output

W:\41597911>dir /B *.jpg
Floor_1_SomeName_PCI_Some Trailing Text.JPG
Floor_1_SomeName_RSRP_Some Trailing Text.JPG
Floor_1_SomeName_RSRQ_Some Trailing Text.JPG
Floor_1_SomeName_RSSI_Some Trailing Text.JPG
Floor_1_SomeName_SINR_Some Trailing Text.JPG
Floor_1_SomeName_TX Power_Some Trailing Text.JPG
Floor_2_SomeName_PCI_Some Trailing Text.JPG
Floor_2_SomeName_RSRP_Some Trailing Text.JPG
Floor_2_SomeName_RSRQ_Some Trailing Text.JPG
Floor_2_SomeName_RSSI_Some Trailing Text.JPG
Floor_2_SomeName_SINR_Some Trailing Text.JPG
Floor_2_SomeName_TX Power_Some Trailing Text.JPG

W:\41597911>sortFiles.cmd
Floor_1_SomeName_RSSI_Some Trailing Text.JPG
Floor_1_SomeName_RSRP_Some Trailing Text.JPG
Floor_1_SomeName_RSRQ_Some Trailing Text.JPG
Floor_1_SomeName_SINR_Some Trailing Text.JPG
Floor_1_SomeName_TX Power_Some Trailing Text.JPG
Floor_1_SomeName_PCI_Some Trailing Text.JPG
Floor_2_SomeName_RSSI_Some Trailing Text.JPG
Floor_2_SomeName_RSRP_Some Trailing Text.JPG
Floor_2_SomeName_RSRQ_Some Trailing Text.JPG
Floor_2_SomeName_SINR_Some Trailing Text.JPG
Floor_2_SomeName_TX Power_Some Trailing Text.JPG
Floor_2_SomeName_PCI_Some Trailing Text.JPG        
MC ND
  • 69,615
  • 8
  • 84
  • 126
  • Thanks, this is very readable. I believe I am following along. keeping this script in the folder path and calling it by CMD sort001.bat /k I can see that it echos the files, I know I can modify your code to write to a text file if need be. But it is not sorted as needed, it just reiterates the names in the sorting format it was originally in. Furthermore, how does this sort the files in the explorer window? – James Hayek Jan 11 '17 at 21:16
  • @JamesHayek, In my case, with the files stored in a NTFS partition, the OS by default retrieves the lis sorted by name. The script outputs the files in the order indicated by the initial variables, BUT this will not change the way the files are sorted in the explorer window. Explorer uses it own sorting code based on column selection. You can change physical file order on a FAT partition, but not on a NTFS, BUT explorer will still use it own code. – MC ND Jan 11 '17 at 22:13
2

I don't used to post code when the OP did not posted his/her own efforts. However, this problem is rather interesting to me, so here it is a solution:

@echo off
setlocal EnableDelayedExpansion

set "order=RSSI RSRP RSRQ SINR "Tx Power" PCI"

rem Extract the "order" string into individual numerated elements
set "i=0"
for %%a in (%order%) do (
   set /A i+=1
   set "order[%%~a]=!i!"
)

rem Process the files and create an array with the desired order
set "lastFloor=0"
for /F "tokens=1-5 delims=_" %%a in ('dir /A:-D /B *.jpg') do (
   set "name[%%b][!order[%%d]!]=%%a_%%b_%%c_%%d_%%e"
   if %%b gtr !lastFloor! set "lastFloor=%%b"
)

rem Process the array elements
for /L %%i in (1,1,%lastFloor%) do (
   for /F "tokens=2 delims==" %%a in ('set name[%%i]') do echo %%a
)

Output:

Floor_1_SomeName_RSSI_Some Trailing Text.JPG
Floor_1_SomeName_RSRP_Some Trailing Text.JPG
Floor_1_SomeName_RSRQ_Some Trailing Text.JPG
Floor_1_SomeName_SINR_Some Trailing Text.JPG
Floor_1_SomeName_TX Power_Some Trailing Text.JPG
Floor_1_SomeName_PCI_Some Trailing Text.JPG
Floor_2_SomeName_RSSI_Some Trailing Text.JPG
Floor_2_SomeName_RSRP_Some Trailing Text.JPG
Floor_2_SomeName_RSRQ_Some Trailing Text.JPG
Floor_2_SomeName_SINR_Some Trailing Text.JPG
Floor_2_SomeName_TX Power_Some Trailing Text.JPG
Floor_2_SomeName_PCI_Some Trailing Text.JPG

You may review the array management in Batch files at this answer.

Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • I'm sorry, I don't know much scripting and didn't know where to start. I am trying to learn from this site and now, from your posted code. Thank you. I do, have a few questions, I will start with one first; how does this script know what directory path I am set? can I modify it with a "set /p path=Directory Path:" command and then call it using %path% ? – James Hayek Jan 11 '17 at 20:27
0

Here is another approach that uses a temporary file; this holds a list of matching file names, which is read multiple times, once per keyword RSSI, RSRP, RSRQ, SINR, TX Power and PCI (reading from a file is better than building the list of files in terms of performance). Here is the code:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILES=.\Floor_*_*_*_*.jpg" & rem // (location and pattern of files to be sorted)

rem // Create temporary file containing list of all matching file names:
> "%~dpn0.tmp" (
    rem // Capture filtered list of files and split them into `_`-separated tokens:
    for /F "tokens=1-4* delims=_" %%A in ('
        dir /B /A:-D /O:N "%_FILES%" ^| ^(
            rem/ Filter for files whose names match the given pattern: ^& ^
            findstr /R /I /C:"^Floor_[0-9][0-9]*_[^_][^_]*_[A-Z ][A-Z ]*_[^_].*\.jpg$"
        ^)
    ') do (
        rem // Pad floor number with leading zeroes:
        set "NUM=0000%%B"
        rem /* Store floor number prefix in variable named `$FLOOR_`, followed by
        rem    four-digit floor number, to get a list of unique floor numbers: */
        call set "$FLOOR_%%NUM:~-4%%=%%A_%%B"
        rem // Write original file name into temporary file:
        echo(%%A_%%B_%%C_%%D_%%E
    )
)
rem /* Loop over the unique floor numbers by retrieving a sorted list of all variables
rem    whose names begin with `$FLOOR_`; the following zero-padded four-digit floor
rem    number ensures ascending numerical sort order (sorted by `set` implicitly): */
for /F "tokens=1,* delims==" %%E in ('2^> nul set $FLOOR_') do (
    rem /* Return file names from temporary file holding the currently iterated floor
    rem    number with the special keywords (fourth token) in the proposed order: */
    findstr /R /I /C:"^%%F_[^_][^_]*_RSSI_" "%~dpn0.tmp"
    findstr /R /I /C:"^%%F_[^_][^_]*_RSRP_" "%~dpn0.tmp"
    findstr /R /I /C:"^%%F_[^_][^_]*_RSRQ_" "%~dpn0.tmp"
    findstr /R /I /C:"^%%F_[^_][^_]*_SINR_" "%~dpn0.tmp"
    findstr /R /I /C:"^%%F_[^_][^_]*_TX Power_" "%~dpn0.tmp"
    findstr /R /I /C:"^%%F_[^_][^_]*_PCI_" "%~dpn0.tmp"
)
rem // Delete temporary file:
del "%~dpn0.tmp"

endlocal
exit /B

Relying on your example data, the aforementioned temporary file contains the following list:

Floor_1_SomeName_PCI_Some Trailing Text.JPG
Floor_1_SomeName_RSRP_Some Trailing Text.JPG
Floor_1_SomeName_RSRQ_Some Trailing Text.JPG
Floor_1_SomeName_RSSI_Some Trailing Text.JPG
Floor_1_SomeName_SINR_Some Trailing Text.JPG
Floor_1_SomeName_TX Power_Some Trailing Text.JPG
Floor_2_SomeName_PCI_Some Trailing Text.JPG
Floor_2_SomeName_RSRP_Some Trailing Text.JPG
Floor_2_SomeName_RSRQ_Some Trailing Text.JPG
Floor_2_SomeName_RSSI_Some Trailing Text.JPG
Floor_2_SomeName_SINR_Some Trailing Text.JPG
Floor_2_SomeName_TX Power_Some Trailing Text.JPG

For every unique floor prefix consisting of Floor_ and a number, the above list is searched for the predefined keywords one after another in the proposed order. To get all the unique floor prefixes, an array-like variable set named $FLOOR_, followed by the floor number, is used, whose respective values hold the floor prefix as they appear in the file names. For these prefixes to appear sorted in an alphanumerical manner, the floor number in the variable names are zero-padded to four digits:

$FLOOR_0001=Floor_1
$FLOOR_0002=Floor_2

The finally returned result is going to be this:

Floor_1_SomeName_RSSI_Some Trailing Text.JPG
Floor_1_SomeName_RSRP_Some Trailing Text.JPG
Floor_1_SomeName_RSRQ_Some Trailing Text.JPG
Floor_1_SomeName_SINR_Some Trailing Text.JPG
Floor_1_SomeName_TX Power_Some Trailing Text.JPG
Floor_1_SomeName_PCI_Some Trailing Text.JPG
Floor_2_SomeName_RSSI_Some Trailing Text.JPG
Floor_2_SomeName_RSRP_Some Trailing Text.JPG
Floor_2_SomeName_RSRQ_Some Trailing Text.JPG
Floor_2_SomeName_SINR_Some Trailing Text.JPG
Floor_2_SomeName_TX Power_Some Trailing Text.JPG
Floor_2_SomeName_PCI_Some Trailing Text.JPG
aschipfl
  • 33,626
  • 12
  • 54
  • 99