我的操作系统是 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
语句,是否可以解决问题?
您需要检查参数是否为空:if "%~1"=="" goto blank
完成后,在 -b 上执行 if/else 开关:if "%~1"=="-b" (goto specific) else goto unknown
用引号将参数括起来可以更容易地检查诸如空白/空/缺少参数之类的内容。 "~" 确保双引号在命令行参数上时被去除。
查看 http://ss64.com/nt/if.html 以获得答案;命令是 IF [%1]==[] GOTO NO_ARGUMENT
或类似的。
"%1"==""
相比,它可以正常工作。我必须在我自己的答案中详细说明这一点。
foo.bat "1st parameter" 2nd_param
。请参阅stackoverflow.com/questions/2541767/…
简短的回答 - 使用方括号:
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.
繁荣 这没有评估为真,也没有评估为假。剧本死了。如果你应该在某个地方关闭反应堆,那么 - 运气不好。你现在会像 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.
但是,在这种情况下,当 "
字符“匹配”(即 - 是偶数)的数量时,我会得到什么:
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]==[-b]
和 "%1"=="-b"
是相同的。由于 win 2000/NT 引入了语法 if "%~1"=="-b"
,其中双引号具有特殊含义,这是您编写脚本的方式,因为它提供了更强大的保护。双引号会转义特殊字符的含义(在命令行中尝试 & | 和 % 字符)。 99.9% 的示例使用双引号语法 - 您的示例 argq bla2" "bla3
仅用于证明方括号的合理性。嵌入式双引号是灾难的秘诀 - 只是说'
cmd
外壳中根本不能引用所有内容(在 - 通过一些转义序列等逐字记录的意义上)。在其他系统中,您有时可以引用所有内容,包括 NUL 字符。 (stackoverflow.com/questions/2730732/…) - 这个问题只是表明,您需要使用一些外部程序。
"key=value"
。我通过在变量(stackoverflow.com/a/51827258/2902367)中替换它们来解决这个问题,然后再检查它是否为空
除了我订阅的其他答案之外,您还可以考虑使用 IF
命令的 /I
开关。
... /I 开关(如果指定)表示进行不区分大小写的字符串比较。
如果您想为用户提供不区分大小写的灵活性来指定参数,这可能会有所帮助。
IF /I "%1"=="-b" GOTO SPECIFIC
您正在比较字符串。如果省略参数,%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 "%~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、方[括号]中思考。
我最近一直在努力在批处理文件中实现复杂的参数切换,所以这是我的研究结果。提供的答案都不是完全安全的,例如:
如果参数包含在引号中(文件名等需要),则 "%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"
File
,它将不会被接受,在这种情况下,您应该只检查exist
或not exist
。这就是为什么你的论点应该定义明确,或者简单地使用 powershell 或 vbScript(如果你是 80 年代......)run.bat "a b"
失败。如果 arg 有空格,"%1"==""
会崩溃。请参阅stackoverflow.com/a/46942471