优秀而有趣的问题(+1)
该空间是由 CMD 解析器的管道机制引入的,而不是由 SORT 引入的。
当您使用 FOR /F 执行命令时,该命令将在其自己的 CMD shell 中执行。此外,管道的每一侧都在其自己的 CMD shell 中执行。请参阅为什么在管道代码块中延迟扩展失败?了解更多信息。
因此,您的命令实际上实例化了 3 个 CMD 外壳,一个用于 FOR /F 命令,而后者又为管道的每一侧创建 2 个。
您可以使用 %CMDCMDLINE% 动态变量查看命令是如何被解析并输入到 CMD shell 中的。因为我们是从命令行执行命令,所以我们需要对变量名中的至少一个字符进行两次转义,以便在到达最里面的 CMD shell 之前它不会被扩展。
这是带有结果的命令(前导>
是我的命令提示符):
>for /f "delims=" %a in ('(echo %^^^cmdcmdline%^&for /l %z in (1,1,10^) do @echo %z^)^|sort') do @echo %a0
1 0
10 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
C:\Windows\system32\cmd.exe /S /D /c" ( echo %cmdcmdline% & FOR /L %z in (1 1 10) do @ echo %z )" 0
输出的最后一行是用于管道左侧的命令行。您可以看到解析器如何在许多地方添加空格。
您可以通过使用简单的批处理脚本来回显值而不是 ECHO 命令来规避该问题。
echoArgs.bat
@echo(%*
现在,当您运行此命令时,您将获得所需的结果
>for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echoArgs %z^)^|sort') do @echo %a0
10
100
20
30
40
50
60
70
80
90
另一种规避该问题的方法是使用 ECHO 命令创建一个变量并适当地转义该变量的扩展。
>set cmd=@(echo %z)
>for /f "delims=" %a in ('(for /l %z in (1,1,10^) do %^^^cmd%^)^|sort') do @echo %a0
10
100
20
30
40
50
60
70
80
90
编辑
这个>_tempfile echo and here's a space|more
例子也很有趣。输出文件末尾有一个额外的空间。但是 Chad Nouis 是正确的,因为左侧的重定向,什么都没有被排序。任何命令都可以在右侧使用,结果是一样的。
问题的根源仍然是解析器,但是解析器重组命令的方式很有趣。
>>_tempfile echo %^cmdcmdline%|rem
>type _tempfile
C:\Windows\system32\cmd.exe /S /D /c" echo %cmdcmdline% 1>_tempfile"
注意重定向是如何从命令的开头移动到结尾的,并且1
显式添加了文件句柄。您当然可以看到额外空间的来源。