James Hayek
James Hayek

Reputation: 653

Sort files by two string in file name: Batch File

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?

Upvotes: 1

Views: 1398

Answers (3)

aschipfl
aschipfl

Reputation: 34909

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

Upvotes: 0

MC ND
MC ND

Reputation: 70923

@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        

Upvotes: 3

Aacini
Aacini

Reputation: 67216

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.

Upvotes: 2

Related Questions