这是记录在案的行为,分号被视为空格(不是由for
循环,而是由执行echo
命令的子shell)。这会导致分号被替换为空格,从而echo field3 is %%c
产生输出field3 is mysubfield31 mysubfield32
。从内部循环中删除delims=;
,因此它使用默认分隔符(空格和制表符),或者选择不同的分隔符,您的脚本应该按预期工作。但是请注意,当嵌套“数组”的字段包含空格时,依赖内部循环中的默认分隔符可能会产生不希望的结果。
证明:
根本原因的证明:
for /f "tokens=*" %%a in ('echo.a#b;c#d^|find ";"') do echo _%%a_
输出:无(即在回显的字符串中找不到分号)
for /f "tokens=*" %%a in ('echo.a#b;c#d^|find " "') do echo _%%a_
输出:_a#b c#d_
显然这适用于所有分隔符(,
, ;
, =
, 空格和制表符),因为我可以用它们中的每一个来重现这种行为。
带有输入字符串的简化脚本a#b;c#d
:
@echo off
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=;" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
输出:
field1 is a
field2 is b c
field3 is d
subfield3 is b c
subfield3 is
注意输出的第2行b
和第4行之间的空格。c
与 2. 相同的脚本,但delims=;
已从内部循环中删除:
@echo off
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
输出:
field1 is a
field2 is b c
field3 is d
subfield3 is b
subfield3 is c
请注意,嵌套的“数组” b;c
(来自变量%foo%
)现在被处理为正确的输出(第 4 行和第 5 行)。这是因为空格和制表符是for /f
循环中的默认分隔符。
与 2. 相同的脚本,但+
用作嵌套“数组”的分隔符:
@echo off
set "foo=a#b+c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=+" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
输出:
field1 is a
field2 is b+c
field3 is d
subfield3 is b
subfield3 is c
请注意,第二个输出行不再包含虚假空间,并且嵌套的“数组”再次被正确处理(第 4 行和第 5 行)。
为了完整性:更好的解决方案是完全放弃echo
并简单地在双引号字符串上循环,正如foxidrive和Peter Wright所建议的那样,因为它完全避免了这个问题。
@echo off
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ("%foo%") do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=;" %%k in ("%%b") do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
dbenham 提出的另一个解决方案是启用延迟扩展并在运行时扩展变量:
@echo off
setlocal EnableDelayedExpansion
set "foo=a#b;c#d"
for /f "tokens=1-3 delims=#" %%a in ('echo !foo!') do (
echo field1 is %%a
echo field2 is %%b
echo field3 is %%c
for /f "tokens=1-2 delims=;" %%k in ('echo %%b') do (
echo subfield3 is %%k
echo subfield3 is %%l
)
)
然而,更好的解决方案是完全放弃批处理并切换到实际支持数组的语言,例如 PowerShell。