如何检查“.bat”文件中的命令行参数?

Posted

技术标签:

【中文标题】如何检查“.bat”文件中的命令行参数?【英文标题】:How to check command line parameter in ".bat" file? 【发布时间】:2011-06-24 14:26:15 【问题描述】:

我的操作系统是 Windows Vista。我需要有一个“.bat”文件,我需要在其中检查用户是否输入了任何命令行参数。如果是,那么如果参数等于-b,那么我会做一些事情,否则我会标记“无效输入”。如果用户没有输入任何命令行参数,那么我会做一些事情。我创建了以下 .bat 文件。它适用于 -b 和不等于 -b 的情况 - 但当用户不传递任何命令行参数时它会失败。

我总是出错:

GOTO was unexpected at this time.

谁能告诉我我在这里做错了什么?


ECHO OFF
CLS
ECHO.

IF [%1]==[/?] GOTO BLANK

IF %1=="-b" GOTO SPECIFIC

IF NOT %1=="-b" GOTO UNKNOWN

:SPECIFIC

ECHO SPECIFIC

GOTO DONE

:BLANK

ECHO No Parameter

GOTO DONE

:UNKNOWN

ECHO Unknown Option

GOTO DONE

:DONE

ECHO Done!

【问题讨论】:

如果在另外两个IF 语句中添加括号(如在GOTO BLANK 行中),是否可以解决问题? 【参考方案1】:

需要检查参数是否为空:if "%~1"=="" goto blank

完成此操作后,请在 -b 上执行 if/else 开关:if "%~1"=="-b" (goto specific) else goto unknown

用引号将参数括起来可以更轻松地检查诸如空白/空/缺失参数之类的内容。 "~" 确保双引号在命令行参数上时被去除。

【讨论】:

这行得通!只有“else”不被接受。我收到错误:“else”不被识别为内部或外部命令、可运行程序或批处理文件。所以我为“不等于-b”的情况添加了另一个IF。感谢您的快速回答。 ELSE 必须和 IF 在同一行,或者直接在括号之后 如果 %1 包含空格,这似乎对我不起作用,如果它是可执行文件的完整路径,可能就是这种情况。请参阅 Jeremiah Willcock's answer 以获取即使对于值中包含空格的参数也有效的解决方案。 如果您的论点是File,它将不会被接受,在这种情况下,您应该只检查existnot exist。这就是为什么你的论点应该定义明确,或者简单地使用 powershell 或 vbScript(如果你是 80 年代......) run.bat "a b" 失败。如果 arg 有空格,"%1"=="" 会崩溃。见***.com/a/46942471【参考方案2】:

查看http://ss64.com/nt/if.html 以获得答案;命令是IF [%1]==[] GOTO NO_ARGUMENT 或类似的。

【讨论】:

这不仅有效!与"%1"=="" 相比,它可以正常工作。我必须在自己的答案中详细说明。 这会在 %1 被引用时中断,例如foo.bat "1st parameter" 2nd_param。见***.com/questions/2541767/… 如果引用了 arg,则使用 [%1]==[-b] 将不匹配。示例run.bat "-b"。见***.com/a/46942471 即使引用了参数,这也对我有用。例如foo.bat "1st parameter" 在我的测试中运行良好。方括号似乎比 IF "%1"==""【参考方案3】:

您正在比较字符串。如果省略参数,%1 将扩展为空白,因此命令变为 IF =="-b" GOTO SPECIFIC 例如(这是语法错误)。将字符串用引号(或方括号)括起来。

REM this is ok
IF [%1]==[/?] GOTO BLANK

REM I'd recommend using quotes exclusively
IF "%1"=="-b" GOTO SPECIFIC

IF NOT "%1"=="-b" GOTO UNKNOWN

【讨论】:

如果 [%1]==[/?] 不工作,但如果我做 IF [%1]==[] 或 "%1"=="",那么它工作。无论如何,现在我可以开始了。感谢您的快速回复。【参考方案4】:

除了我订阅的其他答案,您可以考虑使用IF 命令的/I 开关。

... /I 开关(如果指定)表示进行不区分大小写的字符串比较。

如果您想为用户提供不区分大小写的灵活性来指定参数,这可能会有所帮助。

IF /I "%1"=="-b" GOTO SPECIFIC

【讨论】:

【参考方案5】:

简短的回答 - 使用方括号:

if [%1]==[] goto :blank

或(当您需要处理带引号的参数时,请参阅下面的编辑):

if [%~1]==[] goto :blank

为什么?你可能会问。好吧,正如 Jeremiah Willcock 提到的:http://ss64.com/nt/if.html - 他们使用它!好的,但是引号有什么问题?

再次,简短的回答:它们是“神奇的” - 有时双(双)引号会转换为单(双)引号。首先,它们需要匹配。

考虑一下这个小脚本:

@rem argq.bat
@echo off

:loop 
if "%1"=="" goto :done
echo %1
shift
goto :loop

:done
echo Done.

让我们测试一下:

C:\> argq bla bla
bla
bla
Done.

似乎有效。但是现在,让我们切换到二档:

C:\> argq "bla bla"
bla""=="" was unexpected at this time.

Boom 这没有评估为真,也没有评估为假。剧本死了。如果你应该在某个地方关闭反应堆,那么 - 运气不好。你现在会像 Harry Daghlian 一样死去。

你可能会想——好吧,参数不能包含引号。如果他们这样做,就会发生这种情况。 以下是一些安慰:

C:\> argq ""bla bla""
""bla
bla""
Done.

哦,是的。别担心 - 有时工作。

让我们尝试另一个脚本:

@rem args.bat
@echo off

:loop 
if [%1]==[] goto :done
echo %1
shift
goto :loop

:done
echo Done.

您可以自己测试一下,它是否适用于上述情况。这是合乎逻辑的——引号与括号无关,所以这里没有魔法。但是用括号给 args 增添趣味呢?

D:\>args ]bla bla[
]bla
bla[
Done.

D:\>args [bla bla]
[bla
bla]
Done.

那里没有运气。方括号不能阻塞cmd.exe 的解析器。

让我们暂时回到邪恶的名言。 问题就在那里,当参数以引号结束时:

D:\>argq "bla1 bla2"
bla2""=="" was unexpected at this time.

如果我通过了怎么办:

D:\>argq bla2"
The syntax of the command is incorrect.

脚本根本不会运行。 args.bat 也一样:

D:\>args bla2"
The syntax of the command is incorrect.

但是,在这种情况下,当"-characters “匹配”的数量(即 - 是偶数)时,我会得到什么:

D:\>args bla2" "bla3
bla2" "bla3
Done.

NICE - 我希望您了解.bat 文件如何拆分它们的命令行参数(提示:*这与 bash 中的不完全一样)。上面的参数包含一个空格。但引号不会自动剥离。

还有 argq?它对此有何反应?可想而知:

D:\>argq bla2" "bla3
"bla3"=="" was unexpected at this time.

所以 - 在你说:“知道吗?只需使用引号。[因为,对我来说,这看起来更好]”。

编辑

最近,有一些关于这个答案的 cmets - 好吧,方括号“无法处理”传递引用的参数并将它们视为没有被引用。

语法:

if "%~1"=="" (...)

这不是双引号的一些新发现的优点,而是显示从参数变量中去除引号的简洁功能,如果第一个和最后一个字符是双引号。

这种“技术”与方括号一样有效:

if [%~1]==[] (...)

指出这一点很有用,所以我也赞成新的答案。

最后,双引号的粉丝们,您的书中是否存在"" 形式的参数,还是空白?只是问问;)

【讨论】:

如果 arg 像 run.bat "-b" 一样被引用,方括号 [%1]==[-b] 将不匹配。见***.com/a/46942471 历史记录:[%1]==[-b]"%1"=="-b" 对于 win 98 和更早的 MS/PC-DOS 系统批处理脚本是相同的。由于 win 2000/NT 引入了语法if "%~1"=="-b",其中双引号具有特殊含义,这是您应该编写脚本的方式,因为它提供了更强大的保护。双引号会转义特殊字符的含义(在命令行中尝试 & | 和 % 字符)。 99.9% 的示例使用双引号语法 - 您的示例 argq bla2" "bla3 仅用于证明方括号的合理性。嵌入的双引号是灾难的秘诀 - 只是说' @SkipR - 这就是为什么在 Windows 的文件系统中,您不能在名称中包含这些特殊字符。我没有数学证明,但我认为在cmd shell 中根本不能引用所有内容(在 - 通过一些转义序列等逐字逐句的意义上)。在其他系统中,您有时可以引用所有内容,包括 NUL 字符。 (***.com/questions/2730732/…) - 这个问题只是显示,你需要使用一些外部程序。【参考方案6】:

实际上,所有其他答案都有缺陷。最可靠的方法是:

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

详细说明:

如果使用空格和引号传递参数,使用"%1"=="-b" 将彻底崩溃。这是最不可靠的方法。

IF "%1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "a b"

b""=="-b" was unexpected at this time.

使用[%1]==[-b] 更好,因为它不会因空格和引号而崩溃,但如果参数被引号包围,它将不匹配。

IF [%1]==[-b] (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "-b"

(does not match, and jumps to UNKNOWN instead of SPECIFIC)

使用"%~1"=="-b" 是最可靠的。 %~1 将去掉周围的引号(如果存在)。所以它可以带引号和不带引号,也可以不带参数。

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat
C:\> run.bat -b
C:\> run.bat "-b"
C:\> run.bat "a b"

(all of the above tests work correctly)

【讨论】:

这不是方括号的结尾,你看:IF [%~1]==[] - 这有效,它甚至可以处理"-b"。您只需要能够框、erm、方[括号]中思考。【参考方案7】:

我最近一直在努力在批处理文件中实现复杂的参数切换,所以这是我的研究结果。所提供的答案都不是完全安全的,例如:

"%1"=="-?" 如果参数包含在引号中(文件名等需要)将不匹配,或者如果参数包含在引号中并且包含空格(在文件名中也经常出现),则"%1"=="-?" 将崩溃

@ECHO OFF
SETLOCAL
echo.
echo starting parameter test...
echo.
rem echo First parameter is %1
if "%1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)
C:\>test.bat -?

starting parameter test...

Condition is true, param=-?

C:\>test.bat "-?"

starting parameter test...

Condition is false, param="-?"

如果参数在引号中包含空格,则任何与方括号 [%1]==[-?][%~1]==[-?] 的组合都会失败:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if [%~1]==[-?] (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat "long file name"

starting parameter test...

First parameter is "long file name"
file was unexpected at this time.

建议的最安全的解决方案"%~1"=="-?" 将因包含引号外的文本和引号内的空格的复杂参数而崩溃:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if "%~1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat -source:"long file name"

starting parameter test...

First parameter is -source:"long file name"
file was unexpected at this time.

确保涵盖所有上述情况的唯一方法是使用EnableDelayedExpansion 并使用变量通过引用(而不是通过值)传递参数。那么即使是最复杂的场景也能正常工作:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
echo.
echo starting parameter test...
echo.
echo First parameter is %1
:: we assign the parameter to a variable to pass by reference with delayed expansion
set "var1=%~1"
echo var1 is !var1!
:: we assign the value to compare with to a second variable to pass by reference with delayed expansion
set "var2=-source:"c:\app images"\image.png"
echo var2 is !var2!
if "!var1!"=="!var2!" (echo Condition is true, param=!var1!) else (echo Condition is false, param=!var1!)
C:\>test.bat -source:"c:\app images"\image.png

starting parameter test...

First parameter is -source:"c:\app images"\image.png
var1 is -source:"c:\app images"\image.png
var2 is -source:"c:\app images"\image.png
Condition is true, param=-source:"c:\app images"\image.png

C:\>test.bat -source:"c:\app images"\image1.png

starting parameter test...

First parameter is -source:"c:\app images"\image1.png
var1 is -source:"c:\app images"\image1.png
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images"\image1.png

C:\>test.bat -source:"c:\app images\image.png"

starting parameter test...

First parameter is -source:"c:\app images\image.png"
var1 is -source:"c:\app images\image.png"
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images\image.png"

【讨论】:

以上是关于如何检查“.bat”文件中的命令行参数?的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 命令行中使用批处理文件中的参数

如何将参数从 gradle exec 任务传递到命令行

如何将命令行参数传递给 PowerShell ps1 文件

在通过 Iexpress 创建的 exe 文件中使用命令行参数

将 QT 程序作为窗口和命令行运行

如何使用命令行检查Java类的异常终止