0

Im doing a school project where I need to sort a text file by columns chosen by the user using a batch script.

The file looks like this

ID Name Weight Length With Height
052 Chair 1200 100 30 2
077 Bookshelf 5000 120 30 80
096 Cabinet 15000 80 40 85
146 Cupboard 9000 80 60 200
149 Desk 3650 180 100 5
163 Mirror 25800 120 60 70
182 Table 1600 60 60 70

I tried copying the solution from this answer Batch sort by column in file

And modify it for 6 columns, code looks like this:

setlocal DisableDelayedExpansion
(
    for /F "tokens=1-6 delims= " %%A in (%file%) DO (
        set "par1=%%A"
        set "par2=%%B"
        set "par3=%%C"
        set "par4=%%D"
        set "par5=%%E"
        set "par6=%%F"
        setlocal EnableDelayedExpansion
        echo(!par3! !par1! !par2! !par3! !par4! !par5! !par6!
        endlocal
  )
) > data.txt.tmp

for /F "usebackq tokens=1,* delims= " %%A in (`sort data.txt.tmp`) DO (
    echo(%%B
)

So the problems im having is that I want the top row with ID Name etc to be unchanged. Second thing is this code works when sorting by ID and Name but when I get to weight for example it dosnt sort it correctly and i get output like this:

052 Chair 1200 100 30 2
096 Cabinet 15000 80 40 85
182 Table 1600 60 60 70
163 Mirror 25800 120 60 70
149 Desk 3650 180 100 5
077 Bookshelf 5000 120 30 80
146 Cupboard 9000 80 60 200
ID Name Weight Length With Height

Where it just seems to sort by first and second digit resulting in 15000 being put as smaller than 1600

How can i solve these problems in the best way?

Rednil
  • 13
  • 4
  • 2
    Amazing how your data looks almost identical to this [question](https://stackoverflow.com/questions/66227463/how-to-use-sort-command-in-batch-and-sort-over-9) that was just asked yesterday. – Squashman Feb 18 '21 at 14:25
  • Two issues: 1. You have to exclude the headline from sorting using the option `skip=1` for `for /F`; to get it for the output, use `< %file% (set "HL=" & set /P HL="")` and do `echo(%HL%` later. 2. `sort` sorts alphabetically but what you need is alpha-numerical sorting; to achieve that you have to temporarily pad numbers with zeros to the left for them to consist of the same number of digits, then you can alphabetical order equals alpha-numerical order. *N. B.:* You do not need the `par#` variables, neither do you need delayed expansion; just use: `echo(%%C %%A %%B %%C %%D %%E %%F`… – aschipfl Feb 18 '21 at 16:55
  • @aschipfl Thanks for the actual help! – Rednil Feb 18 '21 at 17:24

1 Answers1

0

I would probably accomplish your task like in the following script (see all the explanatory remarks):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILE=%~1"                      & rem // (file with data to be sorted)
set "_SCOL=3"                        & rem // (number of column to sort)
set "_ANUM=#"                        & rem // (alpha-numeric sorting if not empty)
set "_DESC="                         & rem // (descending order if not empty)
set "_TMPF=%TEMP%\%~n0_%RANDOM%.tmp" & rem // (path to temporary file)
rem // Gather TAB character:
for /F "delims=" %%T in ('
    forfiles /P "%~dp0." /M "%~nx0" /C "cmd /C echo/0x09"
') do set "_TAB=%%T"

rem // Read first line of file into variable:
< "%_FILE%" (set "HEAD=" & set /P HEAD="") || exit /B
rem // Write to temporary file:
> "%_TMPF%" (
    rem // Read all but first line from file line by line:
    for /F usebackq^ skip^=1^ delims^=^ eol^= %%L in ("%_FILE%") do (
        rem // Store current line string:
        set "LINE=%%L"
        rem // Extract sort token from current line:
        for /F "tokens=%_SCOL% delims=%_TAB% eol=%_TAB%" %%K in ("%%L") do (
            rem // Store sort token string:
            set "ITEM=%%K"
            rem // Toggle delayed expansion to avoid loss of `!`:
            setlocal EnableDelayedExpansion
            rem // Check if alpha-numeric sorting is desired:
            if defined _ANUM (
                rem // Check whether sort token only consists of decimal figures:
                (for /F "delims=0123456789 eol=0" %%Z in ("!ITEM!") do rem/) || (
                    rem // Zero-pad sort token to the left up to 12 digits:
                    set "ITEM=000000000000!ITEM!" & set "ITEM=!ITEM:~-12!"
                )
            )
            rem // Write (padded) sort token plus delimter plus line string:
            echo(!ITEM!%_TAB%!LINE!
            endlocal
        )
    )
)
rem // Prepare sort option:
if defined _DESC (set "SOPT=/R") else set "SOPT="
rem // Copy first line, do sorting, strip off sort token, write remainder:
for /F "tokens=1* delims=%_TAB% eol=%_TAB%" %%K in ('
    cmd /V /C echo(_!_TAB!!HEAD!^& rem/ ^& ^
        sort %SOPT% "%_TMPF%"
') do echo(%%L
rem // Clean up temporary file:
del "%_TMPF%"

endlocal
exit /B

The path/name of the text file needs to be provided as a command line argument.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Hey man, I got a remark on the exercise and that was that it needs to handle a two part name like "White Desk". In shell i solved it by putting a tab between every column and then using tab as a delim in the sort command. Is there a simple modify to this code to solve it in batch aswell? – Rednil Feb 25 '21 at 16:31
  • Alright, I adapted the script; before _tabs_ and _spaces_ were used as delimiters, now only _tab_ is used… – aschipfl Feb 25 '21 at 21:15