参数中的批次分度

时间:2018-11-16 18:37:18

标签: batch-file parameters delimiter

我发现以下命令可获取除前两个参数以外的所有参数:
for /f "tokens=2,*" %%a in ("%*") do set AFTER_SECOND=%%b
我的问题是我必须在命令中使用“ ^” “,” ,但是批处理将它们视为分隔符,并且不通过它们。
我尝试通过以下命令:"2,5^^3",但不会通过“,”
谢谢您的帮助!

1 个答案:

答案 0 :(得分:0)

打开命令提示符窗口,然后运行cmd /?以获取Windows命令处理器的帮助输出。最后一个帮助页面在上一段中说明,特别是文件名(或任何其他参数字符串)必须用双引号引起来时,即参数字符串包含空格或这些字符之一&()[]{}^=;!'+,`~<|>。请注意,<|>在文件/文件夹名称中无效,但在常规参数字符串中可能是有效的。

接下来在命令提示符窗口call /?中运行。输出帮助说明了如何引用批处理文件参数,包括所有传递的参数引用 %*,该参数完全引用传递给批处理文件的所有参数字符串,但参数0(即批处理)除外文件名与用户在命令提示符窗口中运行批处理文件时键入的文件名完全相同。

现在让我们看一个名为Test.bat的非常简单的批处理文件:

@echo off
echo %0 %*
for /F "tokens=3*" %%I in ("%*") do echo FOR: %%I %%J
pause

Test.bat在命令提示符窗口中使用以下命令执行:

Test 1 2 3 4 5 6

第二个命令行输出的行与上面写的完全一样。

但是 FOR 在这种情况下会做什么?

在命令提示符窗口中运行for /?会输出命令 FOR 的帮助,并说明选项/F以及tokens=3*的含义。

FOR 在这里需要一个用双引号括起来的字符串,例如"...",空格/制表符包含双引号。在不以默认的行尾(eol)字符;开头的情况下,应使用空格/制表符将该字符串拆分为子字符串,从而应将 1/3 空格/制表符分隔的子字符串分配给指定的循环变量I和第三个子字符串之后空格/制表符之后的其余字符串应根据ASCII table分配给下一个变量,在这种情况下为J

所以输出是预期的:

Test 1 2 3 4 5 6
FOR: 3 4 5 6

FOR 命令行输出有关运行的提示:

Test ;1 2 3 4 5 6

原因是默认eol=;,并且由 FOR 处理的字符串的开头是分号。仅第二个命令行输出用于运行批处理文件的所用命令行。所以输出就是:Test ;1 2 3 4 5 6

接下来,我们运行Test.bat

Test 1 2 3

输出为:

Test 1 2 3
FOR: 3 

FOR 输出的行尾有空格。

但是在使用以下命令行运行批处理文件时会发生什么?

Test.bat "First argument" "1, 2, 3 in second argument" "^ caret in third argument" "and so on"

第二条命令行输出此行。但是 FOR 必须处理:

""First argument" "1, 2, 3 in second argument" "^ caret in third argument" "and so on""

FOR 无法完全按照您期望的那样解释该字符串,因为您包含多个双引号,即设置为要处理的实际多个参数字符串。

那么如何通过忽略前两个参数字符串到一个用空格分隔的环境变量来获取所有参数,以便以后处理由多个批处理文件参数字符串连接而成的字符串?

一种解决方案是与命令SHIFT一起循环使用命令SET

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "AllArguments="

:ArgLoop
set "Argument=%~3"
if defined Argument (
    set "AllArguments=%AllArguments% %Argument%"
    shift /3
    goto ArgLoop
)
rem Is there no more argument or is the argument string just empty?
set "Argument=%3"
if defined Argument shift /3 & goto ArgLoop

rem All argument strings processed, remove first space from the concatenated string.
if defined AllArguments set "AllArguments=%AllArguments:~1%"

cls
echo The batch file was called with:
echo/
echo %0 %*
echo/
echo All arguments starting from third argument are:
echo/
echo "%AllArguments%"
echo/
endlocal
pause

此批处理文件也称为Test.bat,例如,执行以下命令:

Test.bat "First argument" SecondArgument "^ caret in third argument" "" "Fifth argument!" "1,2,3 | 233 < 234 > 235" "& more arguments" "without or" with,double;quotes=whereby "by mistake last argument has a double" quote at end"

那真是一个可怕的参数列表,无法与批处理文件一起处理。

  • 第三个参数字符串中包含转义字符^,该字符被解释为双引号参数字符串中的文字字符。
  • 第四个参数字符串是一个空的参数字符串。
  • 第五个参数字符串中有!,如果即使在双引号参数字符串中也可以在批处理文件中启用延迟扩展,则第五个参数字符串将被解释为延迟环境变量引用的开始/结尾。
  • 下一个参数字符串包含参数分隔符,和重定向操作符|<>,因为它们在双引号参数字符串中而被解释为文字字符。 / li> 还包括
  • 运算符&,它具有多种含义,例如与2>&1multiple commands in one command line进行重定向时一样,但由于也位于双引号字符串中,因此在这里被解释为文字字符。
  • 由于,;=不在双引号参数字符串中,因此被cmd.exe解释为参数分隔符。
  • 最后但并非最不重要的最后一个参数以"结尾,但不以"开头。

具有上述批处理文件的此命令行的输出每行80列:

The batch file was called with:

Test.bat "First argument" SecondArgument "^ caret in third argument" "" "Fifth a
rgument!" "1,2,3 | 233 < 234 > 235" "& more arguments" "without or" with,double;
quotes=whereby "by mistake last argument has a double" quote at end"

All arguments starting from third argument are:

"^ caret in third argument Fifth argument! 1,2,3 | 233 < 234 > 235 & more argume
nts without or with double quotes whereby by mistake last argument has a double
quote at end""

看起来不错,不是吗。

顺便说一句:在这种情况下,不使用双引号输出%AllArguments%的值是一个好主意,因为在双引号参数字符串之外,所有具有cmd.exe特殊含义的字符。但是可以使用延迟扩展将echo "%AllArguments%"替换为setlocal EnableDelayedExpansion & echo !AllArguments!& endlocal,以输出环境变量AllArguments的字符串值而无需双引号。另请参见How does the Windows Command Interpreter (CMD.EXE) parse scripts?

注释1:该批处理文件演示了命令 SHIFT 不会修改%*引用的所有传递的参数字符串。它仅修改该批处理文件使用的编号参数引用,以在循环中始终处理第三个参数,直到实际上没有更多参数为止。

注2::环境变量的最大大小为8192字节,其中包括变量名称的字节,一个等号(名称和值之间的分隔符)和一个以空字节结尾的字符串。换句话说,分配给环境变量的最大长度为:8192-2-变量名称的长度

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • call /?
  • cls /?
  • echo /?
  • endlocal /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?
  • shift /?

PS:我很确定此代码仍不能正确处理所有参数组合,但是它几乎可以在所有用例中使用。