Windows Batch中的神秘事件,没有正确转义?

时间:2018-01-18 03:42:01

标签: windows batch-file escaping

这是我的Windows批处理脚本的一部分:

@echo cd /data/backup/> working\grab__test

@echo line1 'length($0)^>7{$0^=substr^($0,1 >> working\grab__test

这不是现实世界的代码,只是显示问题的孤立部分。

他们应该在文件grab__test上写行。写入grab__test的是:

line1 'length($0

发生什么事了?如果我没有逃脱>并且=我得到一个更加严重的错误:

1 was unexpected at this time.

什么?为什么那个 1在行的末尾?还有其他数字,为什么不是7?为什么第二行有>转义继续写入文件? 精氨酸!

1 个答案:

答案 0 :(得分:0)

命令行

@echo line1 'length($0)^>7{$0^=substr^($0,1 >> working\grab__test

在命令块之外按预期工作,以(开头,以匹配)结束。没有必要在此命令行中转义等号=并打开括号(。只需将右角括号>转义为另外被解释为重定向运算符。

但是在命令块中它没有按预期工作,因为Windows命令解释器解释未转义的右括号),因为命令块的结尾在(上方的某处开始。因此,在命令块中,未包含在双引号中的参数字符串中的每个)都必须使用插入符^进行转义,以解释为文字字符。

以下是展示这种差异的代码。

@echo off
set "OutputFile=%TEMP%\Test.tmp"
echo Line 1: 'length($0)^>7{$0=substr($0,1 >"%OutputFile%"
>>"%OutputFile%" echo Line 2: 'length($0)^>7{$0=substr($0,1
(
>>"%OutputFile%" echo Line 3: 'length($0^)^>7{$0=substr($0,1
)
for /F "usebackq delims=" %%I in ("%OutputFile%") do echo "%%I"
del "%OutputFile%"
set "OutputFile="

输出结果为:

"Line 1: 'length($0)>7{$0=substr($0,1 "
"Line 2: 'length($0)>7{$0=substr($0,1"
"Line 3: 'length($0)>7{$0=substr($0,1"

代码使用 FOR 循环分别输出每一行,命令 ECHO 用双引号括起来代替type "%OutputFile%",以显示第1行和第1行之间的差异第2行。

在用于写入文件的字符串末尾的1和用于将第1行写入文件的命令行上的重定向操作符>之间有一个空格。此空间是必需的,否则字符1将不会写入文件。但是这个空格字符属于 ECHO 输出的字符串,因此会在文件的尾随空格中生成。

避免此尾随空格的解决方案是指定 ECHO 命令的重定向,就像在第2行和第3行将第2行和第3行写入文件一样。

让我们通过将第一行修改为@echo on来调试此批处理文件,并在命令提示符窗口中运行批处理文件,而不是双击它。 (使用TEMP为此示例输出定义了环境变量C:\Windows\Temp。)

set "OutputFile=C:\Windows\Temp\Test.tmp"

echo Line 1: 'length($0)>7{$0=substr($0,1  1>"C:\Windows\Temp\Test.tmp"

echo Line 2: 'length($0)>7{$0=substr($0,1 1>>"C:\Windows\Temp\Test.tmp"

(echo Line 3: 'length($0)>7{$0=substr($0,1 1>>"C:\Windows\Temp\Test.tmp"
 )

for /F "usebackq delims=" %I in ("C:\Windows\Temp\Test.tmp") do echo "%I"

echo "Line 1: 'length($0)>7{$0=substr($0,1 "
"Line 1: 'length($0)>7{$0=substr($0,1 "

echo "Line 2: 'length($0)>7{$0=substr($0,1"
"Line 2: 'length($0)>7{$0=substr($0,1"

echo "Line 3: 'length($0)>7{$0=substr($0,1"
"Line 3: 'length($0)>7{$0=substr($0,1"

del "C:\Windows\Temp\Test.tmp"

set "OutputFile="

在执行之前预处理每个命令行或整个命令块之后,某些命令行确实执行了与批处理文件中写入的不同。

在命令行上,将第一行输出到文件>中,修改为 1>,即插入一个空格1。因此,$0,1之间有两个空格可写入文件,1> STDOUT 重定向到指定文件。这就是为什么$0,1之后的第一个空格也写入文件的原因。

在命令行输出第二行和第三行时,左侧指定的重定向 ECHO 现在位于 1>>的右侧,而不仅仅是>>,只有一个空格在$0,11>>之间。出于这个原因,这两行被写入文件而没有尾随空格。

同样有趣的是Windows命令解释器如何重命名命令块。

每当批处理文件未按预期运行时,强烈建议您将@echo off修改为@echo on或删除该行,或使用 REM 命令将其注释掉(或无效标签::)并在命令提示符窗口中运行批处理文件,以查看在预处理每个命令行和命令块之后Windows命令解释程序实际执行的内容。