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

我的操作系统是 Windows Vista。我需要一个。Bat”文件,我需要检查用户是否输入任何命令行参数。如果是这样,那么如果参数等于 -b,那么我将做一些事情,否则我将标记“无效输入”。如果用户没有输入任何命令行参数,那么我将做一些事情。我创造了追随者。蝙蝠档案。它适用于 -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!
242692 次浏览

You need to check for the parameter being blank: if "%~1"=="" goto blank

Once you've done that, then do an if/else switch on -b: if "%~1"=="-b" (goto specific) else goto unknown

在参数周围加上引号可以更容易地检查空白/空白/缺失的参数。”确保如果双引号位于命令行参数上,它们将被去掉。

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

你在比较字符串。如果省略了一个参数,则 %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

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

.../I 开关,如果指定,说做不区分大小写的字符串比较。

如果您希望为用户指定参数提供不区分大小写的灵活性,那么它可能会有所帮助。

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

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

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

或者(如果需要处理引用的参数,请参阅下面的编辑) :

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

为什么?你可能会问。就像 Jeremiah Willcock 提到的: http://ss64.com/nt/if.html——他们用这个!好吧,但是引用有什么问题吗?

Again, short answer: they are "magical" - sometimes double (double) quotes get converted to a single (double) quote. And they need to match, for a start.

想想这个小剧本:

@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.

您可以测试自己,它在上述情况下是否工作正常。这是符合逻辑的——引号和括号没有任何关系,所以这里没有魔法。但是用括号给参数加点料怎么样?

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


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

这里运气不好。括号不能阻塞 cmd.exe的解析器。

Let's go back to the evil quotes for a moment. 问题就在这里,当争论以一句话结束时:

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 - I hope you learned something about how .bat files split their command line arguments (HINT: *It's not exactly like in bash). The above argument contains a space. But the quotes are not stripped automatically.

那 argq 呢? 它对此作何反应? 可以预见:

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

所以——在你说: “知道什么? 就用引号吧。(因为,对我来说,这样看起来更好)”之前先想一想。

剪辑

Recently, there were comments about this answer - well, sqare brackets "can't handle" passing quoted arguments and treating them just as if they weren't quoted.

The syntax:

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

不是一些新发现的双引号的优点,而是从参数变量中剥离引号的一个简洁特性的显示,如果第一个和最后一个字符是双引号。

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

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

指出这一点很有用,所以我也支持这个新的答案。

Finally, double quote fans, does an argument of the form "" exist in your book, or is it blank? Just askin' ;)

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

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.

Using [%1]==[-b] is better because it will not crash with spaces and quotes, but it will not match if the argument is surrounded by quotes.

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)

I've been struggling recently with the implementation of complex parameter switches in a batch file so here is the result of my research. None of the provided answers are fully safe, examples:

如果参数用引号括起来(需要用于文件名等) ,那么 "%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.

The proposed safest solution "%~1"=="-?" will crash with a complex parameter that includes text outside the quotes and text with spaces within the quotes:

@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.

The only way to ensure all above scenarios are covered is to use 启用延迟扩展 and to pass the parameters by reference (not by value) using variables. Then even the most complex scenario will work fine:

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