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


103

我的操作系统是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!

如果GOTO BLANK在其他两个IF语句中添加方括号(如该行所示),是否可以解决问题?
Jeremiah Willcock

Answers:


141

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

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

用引号将参数引起来使检查空白/空/缺失参数等操作变得更加容易。“〜”确保双引号在命令行参数中被去除。


这有效!!仅“其他”不被接受。我收到错误消息:“ else”未被识别为内部或外部命令,可操作程序或批处理文件。因此,我为“不等于-b”的情况添加了另一个IF。感谢您及时回复。
javauser71 2011年

7
ELSE必须与IF在同一行,或者必须
紧接

4
如果%1包含空格,这似乎对我不起作用,如果它是可执行文件的完整路径,则可能是这种情况。请参见耶利米·威尔科克(Jeremiah Willcock)的答案,该解决方案甚至适用于值中带有空格的参数。
马克·菲茨杰拉德

如果您的参数为File,则将不接受该参数,在这种情况下,您应仅检查existnot exist。这就是为什么你的论点要明确定义,或者干脆使用PowerShell或VBScript(如果你在80年代是..)

1
失败run.bat "a b""%1"==""如果arg有空格,则崩溃。参见stackoverflow.com/a/46942471
wisbucky

27

http://ss64.com/nt/if.html上找到答案;该命令是IF [%1]==[] GOTO NO_ARGUMENT或类似的。


1
这不仅还起作用!与相比,它只是有效"%1"==""。我必须在我自己的答复中详细说明。
Tomasz Gandor

1
引用%1时,这将中断,例如foo.bat "1st parameter" 2nd_param。见stackoverflow.com/questions/2541767/...
马特·威尔基

[%1]==[-b]如果引用arg,则使用将不匹配。实例run.bat "-b"。参见stackoverflow.com/a/46942471
wisbucky

20

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

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.

繁荣这没有评估为true,也没有评估为false。脚本已死。如果您应该关闭反应堆的某个地方,那么,祝您好运。您现在将像哈里·达格利安(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.

那里没有运气。括号不能cho住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.

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

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

NICE-希望您了解了.bat文件如何拆分命令行参数的一些信息(提示:*与bash并不完全一样)。上面的参数包含一个空格。但是引号不会自动删除。

还有argq?它对此有何反应?可以预期地:

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

所以-想想您说什么:“知道什么?只用引号。[因为对我来说,这看起来更好]”。

编辑

最近,对此答案发表了评论-好吧,方括号“无法处理”传递引用的参数并将其视为未引用一样。

语法:

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

不是双引号的一些新发现的优点,而是显示了一个精巧的功能,即如果第一个和最后一个字符是双引号,则从参数变量中删除引号。

这种“技术”与方括号同样适用:

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

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

最后,双引号迷,""您的书中是否存在表格形式的参数,还是空白?就像阿斯金';)


1
[%1]==[-b]如果将arg引用为,则方括号将不匹配run.bat "-b"。参见stackoverflow.com/a/46942471
wisbucky

历史记录:对于Win 98和更早的MS / PC-DOS系统批处理脚本[%1]==[-b]"%1"=="-b"它们是相同的。自从Win 2000 / NT引入语法以来if "%~1"=="-b",双引号具有特殊含义,这是您应该编写脚本的方式,因为它提供了更强大的保护。双引号转义特殊字符(命令行中的&和|%char)的含义。99.9%的示例使用双引号语法-您的示例argq bla2" "bla3仅是用于证明方括号的情况。嵌入的双引号是灾难的根源-只是说
跳过R

@SkipR-这就是为什么在Windows的文件系统中,名称中不能包含这些特殊字符的原因。我没有数学上的证明,但我认为在cmd外壳程序中不能简单地引用所有内容(通过逐个转义序列等方式逐字逐句地引用)。在其他系统中,有时可以引用所有内容,包括NUL字符。(stackoverflow.com/questions/2730732/…)-这个问题刚刚显示,您需要使用一些外部程序。
Tomasz Gandor

8

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

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

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

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

5

您正在比较字符串。如果省略了参数,则将其%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] == [/?]不起作用,但如果[%1] == []或“%1” ==“”,我就可以了。无论如何,我现在可以走了。谢谢你快速的回复。
javauser71 2011年

5

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

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)

1
您不会看到方括号的结尾:IF [%~1]==[]-可行,甚至可以处理"-b"。您只需要能够在盒子内部,erm,方形[方括号]中思考。
Tomasz Gandor

3

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

"%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"

0

Windows批处理为此具有DEFINED关键字。

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar

谢谢大卫。我不知道为什么在IF和IF NOT之间没有回车和换行。我什至没有注意到。
查尔斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.