Windows 复制命令以非数字顺序连接多个文件

Windows 复制命令以非数字顺序连接多个文件

我有一个文件夹,里面有大约 5000 个.ts文件,我想将它们合并为一个。它们遵循命名格式,例如,chunk_n等等chunk_50。当我运行 Windows 复制命令时,如下所示:chunk_51chunk_52

copy /b *.ts final.ts

它不会按照正常数字顺序对它们进行迭代。它将按照以下顺序开始连接它们:

chunk_100,,,,,,,,,,,,chunk_1000chunk_1001chunk_1002chunk_1003chunk_1004chunk_1005chunk_1006chunk_1007chunk_1008chunk_1009chunk_101

等等。

它在迭代时似乎不会查看整个文件名。即使我删除了chunk_之前的文件名,并将它们全部命名为 1 到 5000,问题仍然存在。这是预期的行为吗?有没有更好的方法来连接所有这些文件?

答案1

在大多数程序中,数字顺序从来没有正常顺序。直到最近,文件管理器(例如 Windows 资源管理器)才开始使用“自然排序”对文件进行排序,但命令copy和排序*尚未进行相应的更改。

相反,*扩展按文件名的 ASCII 进行排序字节顺序,分别比较每个字符。例如,对于“chunk_1000.ts”与“chunk_101.ts”(扩展名是名称的一部分),前 8 个字节(chunk_10)相等,然后是0 <  1(零是 ASCII 48,一是 ASCII 49),因此chunk_100(0.ts) <  chunk_101(.ts)– 即使后面还有更多数字,它们也根本不被视为整个“数字”的一部分。

(字节顺序是排序名称的最直接方式——只需直接比较两个内存位置即可。当 RAM 以千字节为单位测量时,这种简单性非常重要。现在这种情况已经持续了 50 年,所以现在几乎不可能改变,因为许多依赖于现有行为的脚本。

最简单的解决方法是将所有数字填充到固定宽度,例如chunk0050 chunk0100

在更高级的 shell(例如 PowerShell 或 Bash)中,可以使用另一种解决方法,即获取输入列表并将其作为单独的步骤进行排序。例如,在 Linux 上,您可以使用外部“sort”或“natsort”命令来获取所需的顺序(它们并不是 Bash 的真正组成部分,但通常存在于 Bash 所在的任何地方):

(printf '%s\n' chunk*.ts | sort -V | xargs -d'\n' cat) > allchunks.ts

在 PowerShell 中,Sort-Object可以指定自定义比较器;没有针对“自然”(数字)顺序的预定义比较器,但是从这里你可以借用一句话:

$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$filenames = Get-ChildItem chunk*.ts | Sort-Object $ToNatural
$filenames = $filenames -join "+"
cmd /c "copy $filenames allchunks.ts"

答案2

文件名为名称,而不是数字,因此将它们作为文本字符串进行比较,使用字典顺序。chunk_1在...之前chunk_10在...之前在...chunk_10a之前在...之前chunk_1z在...之前chunk_2

如果可用,您可以使用以下命令:

<*.ts(n) >final.ts

这利用了 zsh 的功能组合:

如果还有基本的类 Unix 实用程序可用,则可以使用cat连接文件的命令:

cat *.ts(n) >final.ts

Zsh 可通过西弗吉尼亚海岸sudo apt-get install zsh),赛格威以及可能的其他适用于 Windows 的免费软件发行版。

答案3

Windowscopy命令是CMD.EXE内置命令。它根本不对通配符扩展进行排序。此行为至少可以追溯到 MS-DOS 6.22 COMMAND.COM(我手头没有任何更早的版本可以测试)。碰巧的是,您的 NTFS 文件系统将文件名存储在 B 树结构中,其效果是按照接近词汇排序顺序的顺序枚举它们。

更多信息请参阅 Old New Thing 博客:

为什么 NTFS 和 Explorer 在文件名排序上不一致?

如果没有指定排序顺序,DIR 命令将按什么顺序排列文件?

答案4

这是另一个电源外壳方法:

Get-ChildItem *.cs |
    Sort-Object { [Int]( $_.BaseName -replace ('\D+','') ) } |
        Get-Content |
            Add-Content ConCat.cs

别名:

gci *.cs | Sort {[Int]($_.BaseName -replace ('\D+',''))} | gc | ac ConCat.cs

相关内容