echo与管道一起使用时会增加空间

时间:2012-06-08 12:25:48

标签: batch-file

在回答this问题时,我发现了一些我没有解释的奇怪行为

for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echo %z^)') do @echo %a0

你会看到数字10..100,现在只需添加管道,例如到sortmore,无论如何:

for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echo %z^)^|sort') do @echo %a0

%a0之间会添加空格! 看起来像通过管道回声的东西会增加一个尾随空格,可以很容易看出来:

>_tempfile echo no space here
>_tempfile echo and here's a space|more

甚至

>_tempfile <nul set /p =also a space|sort

(可能使用echo来打印提示)

当没有输出重定向(无论是文件还是命令)时,都不会发生这种情况。 这是一个错误还是我错过了什么?我如何摆脱空间? (除了使用var:~0,-1)剥离最后一个字符的肮脏黑客

2 个答案:

答案 0 :(得分:8)

优秀而有趣的问题(+1)

空间由CMD解析器的管道机制引入,而不是由SORT。

引入

使用FOR / F执行命令时,该命令在其自己的CMD shell中执行。此外,管道的每一侧都在其自己的CMD shell中执行。有关详细信息,请参阅Why does delayed expansion fail when inside a piped block of code?

因此,您的命令实际上实例化了3个CMD shell,一个用于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的文件句柄。你当然可以看到额外空间的来源。

答案 1 :(得分:0)

重定向运算符适用于它们最接近的命令 - 而不是整行。

在您的三个测试用例中,您将echoset命令的标准输出重定向到文件。通过重定向标准输出,没有任何内容可以用于moresort

在你的嵌套for循环示例中,我认为有一些不必要的括号会导致头痛。试试这个:

for /f "delims=" %a in ('for /l %z in (1,1,10^) do @echo %z^|sort') do @echo %a0