在 Windows 中使用批处理脚本对文本文件进行排序

Posted

技术标签:

【中文标题】在 Windows 中使用批处理脚本对文本文件进行排序【英文标题】:Sort a text file with a batch script in windows 【发布时间】:2021-05-21 10:58:58 【问题描述】:

我正在做一个学校项目,我需要按用户使用批处理脚本选择的列对文本文件进行排序。

文件如下所示

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

我尝试从这个答案Batch sort by column in file复制解决方案

并修改为6列,代码如下:

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
)

所以我遇到的问题是我希望带有 ID 名称等的第一行保持不变。第二件事是这段代码在按 ID 和名称排序时有效,但是当我得到权重时,它不会正确排序,我得到如下输出:

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

它似乎只是按第一位和第二位数字排序,导致 15000 小于 1600

我怎样才能以最好的方式解决这些问题?

【问题讨论】:

令人惊讶的是,您的数据与昨天刚刚询问的 question 几乎完全相同。 两个问题: 1. 您必须使用skip=1 for for /F 选项将标题排除在排序之外;要将其用于输出,请使用 < %file% (set "HL=" & set /P HL="") 并稍后执行 echo(%HL%。 2. sort 按字母排序,但您需要的是字母数字排序;要实现这一点,您必须暂时用零填充数字,以使它们包含相同数量的数字,然后您可以按字母顺序等于字母数字顺序。 N. B.: 不需要par# 变量,也不需要延迟扩展;只需使用:echo(%%C %%A %%B %%C %%D %%E %%F... @aschipfl 感谢您的实际帮助! 【参考方案1】:

我可能会像以下脚本一样完成您的任务(请参阅所有解释性说明):

@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

文本文件的路径/名称需要作为命令行参数提供。

【讨论】:

嘿伙计,我收到了关于练习的评论,那就是它需要处理像“White Desk”这样的两部分名称。在 shell 中,我通过在每列之间放置一个制表符,然后在排序命令中使用制表符作为分隔符来解决它。是否有对此代码进行简单修改以批量解决? 好吧,我改编了剧本;之前 tabsspaces 被用作分隔符,现在只使用 tab...

以上是关于在 Windows 中使用批处理脚本对文本文件进行排序的主要内容,如果未能解决你的问题,请参考以下文章

bat脚本学习

如何逐行读取批处理文件中多余字符的文本文件?允许限制行长。(Windows,批处理脚本)

Windows 批处理 - 将多个文本文件连接成一个

shell脚本之awk工具的使用

如何使用Windows命令行环境查找和替换文件中的文本?

bat脚本获取电脑上所有windows服务的信息?