【问题标题】:Read files in directory in order of filename prefix with batch?用批处理按文件名前缀的顺序读取目录中的文件?
【发布时间】:2020-07-15 10:37:54
【问题描述】:

我在一个目录中有许多 SQL 脚本,以数字为前缀,例如

目前,我可以使用以下脚本遍历它们:

@ECHO OFF
FOR /r . %%F IN (*.sql) DO (
    ECHO File:"%%F"
)

但是,由于Windows读取目录中文件的方式,10和11在2之前读取等等:

如何循环遍历目录中的每个文件,按前缀顺序

【问题讨论】:

  • 下面@Aacini的解决方案不错。但是,如果您使用 Powershell,您也可以使用单行代码 Get-ChildItem | Sort-Object { [regex]::Replace($_.Name, '\d+', { $args[0].Value.PadLeft(20) }) }See here for the topic on SO(这就是我没有将其添加为答案的原因)。

标签: windows batch-file


【解决方案1】:

下面的批处理文件在需要它的文件名中插入前导零。

@echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%f in ('dir /B *.sql') do (
   set "filename=%%f"
   if "!filename:~1,1!" equ "-" ren "%%f" "0%%f"
)

编辑:添加了新的解决方案

下面的批处理文件以正确的顺序显示文件,无需重命名。

@echo off
setlocal EnableDelayedExpansion
rem Create an array with filenames in right order
for %%f in (*.sql) do (
   for /F "delims=-" %%n in ("%%f") do (
      set "number=00000%%n"
      set "file[!number:~-6!]=%%f"
   )
)
rem Process the filenames in right order
for /F "tokens=2 delims==" %%f in ('set file[') do (
   echo %%f
)

【讨论】:

  • 您能否简要解释一下您的新解决方案是如何工作的,并提供指向进一步详细说明它的文档的链接?我希望能够对其进行改进,例如,如果没有列出文件,则跳过第二个 for 循环。谢谢!
【解决方案2】:

替代方法!

这不是您问题的直接答案,但可能会达到相同的结果:

FOR /L %%i IN (1,1,11) DO FOR %%f IN (%%i-*.sql) DO ECHO %%f

【讨论】:

    【解决方案3】:

    据我所知,没有 FOR 标志。

    但这里是 pure PowerShell solution 使用某种奇怪的正则表达式。

    或者您可以列出文件,sort 它们,将这些已排序的文件路径按正确顺序放置,然后读取。

    第三种解决方案是尝试使用标准的 Windows Shell 命令和运算符构建一些排序功能。

    【讨论】:

    • 确实很奇怪的正则表达式。
    • “单行”here 更容易。 Get-ChildItem | Sort-Object { [regex]::Replace($_.Name, '\d+', { $args[0].Value.PadLeft(20) }) }
    【解决方案4】:

    编辑 - 使用 JSORT.BAT 的新简单解决方案

    本机批处理 SORT 命令非常有限。我写了一个方便的JSORT.BAT sorting utility,它提供了许多方便的功能,包括根据数值对带有数字的字符串进行排序的能力。 JSORT.BAT 是纯脚本(混合 JScript/批处理),可在任何 Windows 机器上本地运行,无需任何第三方 exe 文件。

    您可以使用数字列出文件

    dir /b /a-d *.sql^|jsort /n /i
    

    如果要迭代结果,只需将命令放在 FOR /F 循环中

    for /f "delims=" %%F in ('dir /b /a-d *.sql^|jsort /n /i') do echo %%F
    

    使用jsort /?,可从命令行获取完整文档。


    早于 JSORT.BAT 的原始解决方案

    可以在不修改文件名的情况下使用批处理执行您想要的操作,如果您使用hybrid JScript/batch utility called REPL.BAT 在标准输入上执行正则表达式搜索和替换并将结果写入标准输出,则效率非常高。该实用程序是纯脚本,可​​在从 XP 开始的任何 Windows 机器上运行 - 不需要第三方可执行文件。完整的文档嵌入在脚本中。

    假设 REPL.BAT 在您的当前目录中,或者更好的是,在您的 PATH 中的某个位置,那么下面的代码将以所需的排序顺序迭代以数字开头的 .sql 文件。如前所述,它支持长达 5 位的数字。它可以轻松扩展以支持更大的数字。

    @echo off
    for /f "tokens=2 delims=:" %%F in (
      'dir /b /a-d *.sql^|repl "^(\d+).*" "00000$1:$&" a^|repl ".*(\d{5}:)" "$1"^|sort'
    ) do echo %%F
    

    这确实显示了管道的力量:)

    复杂的 IN() 子句的工作原理如下:

    1. 列出所有 .sql 文件
    2. 查找以数字开头的文件,并将每个匹配的名称替换为以五个前导零为前缀的前导数字,后跟冒号,后跟原始名称
    3. 替换前导数字,仅保留最后 5 位
    4. 对结果进行排序

    然后父 FOR /F 读取结果,将原始文件名解析为第二个 : 分隔标记。

    【讨论】:

    • EDIT - 我通过使用 FOR /F 解析出原始文件名进行了简化。原始帖子有一个额外的 REPL 步骤来进行解析。
    【解决方案5】:

    根据需要使用前导 0 重命名脚本,以便前缀中的位数始终相同。

    【讨论】:

    • 谢谢,这适用于我当前的用例,但感觉很笨拙,因为每次文件集增长 10 时,您都必须添加另一个前导零。
    【解决方案6】:

    Take Command Console 是一个免费版本的命令解释器,会进行自然排序。

    【讨论】:

      【解决方案7】:

      在批处理中使用 powershell 进行排序的示例:

      FOR /f "usebackq" %%F IN (
        `powershell "ls -r *.sql | sort { [int]($_.Name -replace '\D','') } | %% { $_.FullName }"`
      ) DO (
          ECHO File:"%%F"
      )
      
      • ls -r *.sqlGet-ChildItem -Recurse 的缩写形式)对应于 FOR /r . %%F IN (*.sql) 部分
      • sort { [int]($_.Name -replace '\D','') }sort 之前的文件名中提取数字
      • %% { $_.FullName }ForEach-Object 的缩写形式)打印每个文件的完整路径

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-08
        • 1970-01-01
        • 2019-12-04
        • 2013-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多