测试批处理文件中参数是不是为空的正确方法是啥?
Posted
技术标签:
【中文标题】测试批处理文件中参数是不是为空的正确方法是啥?【英文标题】:What is the proper way to test if a parameter is empty in a batch file?测试批处理文件中参数是否为空的正确方法是什么? 【发布时间】:2011-02-02 06:17:00 【问题描述】:我需要测试是否设置了变量。我尝试了几种技术,但每当%1
被引号包围时它们似乎都失败了,例如%1
是"c:\some path with spaces"
的情况。
IF NOT %1 GOTO MyLabel // This is invalid syntax
IF "%1" == "" GOTO MyLabel // Works unless %1 has double quotes which fatally kills bat execution
IF %1 == GOTO MyLabel // Gives an unexpected GOTO error.
根据this site,这些是受支持的IF
语法类型。所以,我看不出有什么办法。
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
更新:在 2020 年 10 月 25 日,我将接受的答案从使用括号更新为使用波浪号。每个人都说波浪号更好,因为它更安全。我有点心烦意乱,因为波浪号看起来更复杂,而且不太清楚它的目的是什么,但我还是改变了它。
【问题讨论】:
在我的系统(Windows 2003 和 Windows 7)上,if "%1" == "" GOTO MyLabel
不会致命地终止脚本的执行,只要 %1
有偶数个双引号。我看到%1
中的奇数个双引号会导致脚本的执行出现此错误:The syntax of the command is incorrect.
下面使用方括号解决问题的解决方案已被标记为正确答案,但事实并非如此似乎做得更好。当%1
有奇数个双引号时,该解决方案也会失败并出现相同的错误。
@SusamPal 有趣。试试它下面的括号版本,看看是否有效。那个我测试了更多。几天前我刚刚更新了接受的答案。
Dan Story's answer 似乎确实可以正常工作。我使用方括号的版本。
一个很好的“包罗万象”示例:***.com/questions/830565/… 涵盖文件/目录和通用字符串/数字混合参数。
太令人沮丧了——IF DEFINED
只处理环境变量而不是脚本变量真是浪费潜力!
【参考方案1】:
使用方括号代替引号:
IF [%1] == [] GOTO MyLabel
括号不安全:只能使用方括号。
【讨论】:
括号不安全!%1
中的&
之类的内容会断行
使用if #%1#==##
或if [%1]==[]
等其他字符是好的,只要参数中没有空格,否则会出现…was unexpected at this time
错误。
正如我在回答中提到的那样,使用"%~1"
确实是一种更好的方法。
伙计们,@jamesdlin 是正确的。如果变量文本有空格或者是==
,这种方法将不起作用。改用他的答案。
你没有说清楚it DOES NOT work with spaces
。请改用@jamesdlin 答案。【参考方案2】:
你可以使用:
IF "%~1" == "" GOTO MyLabel
去除外部引号。一般来说,这是一种比使用方括号更可靠的方法,因为即使变量中有空格,它也可以工作。
【讨论】:
这确实是一个好方法。通过使用~
,您可以去掉外部引号(如果存在),然后手动添加它们(确保只有一组)。此外,如果参数包含空格,您必须使用引号(当我以前使用#
或括号而不是引号的版本导致带有空格的参数抛出…was unexpected at this time
时,我很难学会这一点错误。)
这是否也适用于像 %MYVAR% 这样的一般变量而不是像 %1 这样的参数?
@simpleuser 哎呀,你是对的,它不适用于一般环境变量。
注意使用双 '"' 作为转义序列的字符串 -- 尝试比较时脚本会崩溃。例如 ""this string will crash the comparison""
。双 '"' 是正确的转义序列,并且正在做如果字符串为空,对双 '"' 的替换将失败。
@Amalgovinus 您可能可以将变量作为参数传递给子程序并让子程序使用"%~1"
。【参考方案3】:
最好的半解决方案之一是将%1
复制到一个变量中,然后使用延迟扩展,如delayedExp。对任何内容始终是安全的。
set "param1=%~1"
setlocal EnableDelayedExpansion
if "!param1!"=="" ( echo it is empty )
rem ... or use the DEFINED keyword now
if defined param1 echo There is something
这样做的好处是处理 param1 是绝对安全的。
而且param1的设置在很多情况下都会起作用,比如
test.bat hello"this is"a"test
test.bat you^&me
但它仍然会出现奇怪的内容,例如
test.bat ^&"&
为了能够得到100%正确的存在答案
它会检测%1
是否为空,但对于某些内容它无法获取内容。
这对于区分空的%1
和""
也很有用。
它利用CALL
命令的能力在不中止批处理文件的情况下失败。
@echo off
setlocal EnableDelayedExpansion
set "arg1="
call set "arg1=%%1"
if defined arg1 goto :arg_exists
set "arg1=#"
call set "arg1=%%1"
if "!arg1!" EQU "#" (
echo arg1 exists, but can't assigned to a variable
REM Try to fetch it a second time without quotes
(call set arg1=%%1)
goto :arg_exists
)
echo arg1 is missing
exit /b
:arg_exists
echo arg1 exists, perhaps the content is '!arg1!'
如果您想 100% 防弹以获取内容,您可以阅读 How to receive even the strangest command line parameters?
【讨论】:
【参考方案4】:来自 IF /?:
如果启用命令扩展 IF 变化如下:
IF [/I] string1 compare-op string2 command IF CMDEXTVERSION number command IF DEFINED variable command
......
DEFINED 条件仅适用 像 EXISTS 一样,除了它需要一个 环境变量名和返回 如果环境变量为 true 已定义。
【讨论】:
是的,我实际上尝试过这种方法,据我所知,这仅适用于 ENVIRONMENT 变量。因此,不适用于 %1 或批处理文件中定义的变量。 这仅适用于%1
等。 “在批处理文件中定义的变量”实际上是批处理文件运行时的环境变量,您可以在它们上使用IF DEFINED
。【参考方案5】:
不幸的是,我没有足够的声誉来评论或投票对我必须自己编写的当前答案。
最初,OP 的问题是“变量”而不是“参数”,这变得非常混乱,特别是因为这是谷歌搜索如何测试空白变量的第一链接。自从我的原始答案以来,Stephan 已经编辑了原始问题以使用正确的术语,但我决定保留它以帮助消除任何混淆,而不是删除我的答案,尤其是在谷歌仍然向这里发送变量的情况下:
%1 不是变量!这是一个命令行参数。
非常重要的区别。一个带数字的百分号表示命令行参数而不是变量。
变量使用 set 命令设置,并使用 2 个百分号调用 - 一个之前和一个之后。例如 %myvar%
要测试空变量,请使用“如果未定义”语法(显式用于变量的命令不需要任何百分号),例如:
set myvar1=foo
if not defined myvar1 echo You won't see this because %myvar1% is defined.
if not defined myvar2 echo You will see this because %myvar2% isn't defined.
(如果您想测试命令行参数,那么我建议参考 jamesdlin 的答案。)
【讨论】:
你是对的。但正确的方法是将标题从if variable is empty
更正为if parameter is empty
。我刚刚做完。 (冒着使某些答案无效的风险,这些答案确实检查了变量而不是参数,因此无论如何都是无效的,因为他们没有回答问题)
好的,谢谢斯蒂芬,没想到你能做到。我已经编辑了答案以反映更新。【参考方案6】:
使用“IF DEFINED 变量命令”来测试批处理文件中的变量。
但如果你想测试批处理参数,请尝试以下代码以避免棘手的输入(例如“1 2”或ab^>cd)
set tmp="%1"
if "%tmp:"=.%"==".." (
echo empty
) else (
echo not empty
)
【讨论】:
【参考方案7】:我根据这里的答案创建了这个小批量脚本,因为有很多有效的。只要您遵循相同的格式,请随意添加:
REM Parameter-testing
Setlocal EnableDelayedExpansion EnableExtensions
IF NOT "%~1"=="" (echo Percent Tilde 1 failed with quotes) ELSE (echo SUCCESS)
IF NOT [%~1]==[] (echo Percent Tilde 1 failed with brackets) ELSE (echo SUCCESS)
IF NOT "%1"=="" (echo Quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1]==[] (echo Brackets one failed) ELSE (echo SUCCESS)
IF NOT "%1."=="." (echo Appended dot quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1.]==[.] (echo Appended dot brackets one failed) ELSE (echo SUCCESS)
pause
【讨论】:
【参考方案8】:你可以使用
if defined (variable) echo That's defined!
if not defined (variable) echo Nope. Undefined.
【讨论】:
欢迎来到 SO!你的回答似乎是对这个问题的一个很好的回答。一旦您拥有足够的 [声誉] (***.com/help/whats-reputation),您就可以在任何帖子上使用 comment。还要检查这个what can I do instead。【参考方案9】:我用下面的代码测试,没问题。
@echo off
set varEmpty=
if not "%varEmpty%"=="" (
echo varEmpty is not empty
) else (
echo varEmpty is empty
)
set varNotEmpty=hasValue
if not "%varNotEmpty%"=="" (
echo varNotEmpty is not empty
) else (
echo varNotEmpty is empty
)
【讨论】:
当变量包含引号时,您的解决方案将失败。顺便说一句,存在语法IF DEFINED var
是有原因的【参考方案10】:
我通常用这个:
IF "%1."=="." GOTO MyLabel
如果 %1 为空,IF 将比较 "."到 ”。”这将评估为真。
【讨论】:
这是不正确的。这与以下内容相同: IF "%1" == "" 这篇文章的原因是如果 %1 本身有引号,则会失败。 您是否尝试测试 %1 是否为空或是否有引号?问题不清楚。如果在命令行上没有为 %1 指定任何内容,我的答案就有效。 > 您是否要测试 %1 是否为空或是否有引号? @aphoria,它必须能够同时处理两者。 我用它来计算是否设置了 %1%,对我来说效果很好。谢谢,很好的答案! aphoria - 请原谅 10 年后的回应,但我今天才读到这个。扩展@blak3r 所说的内容...例如,您的批处理文件名为batch.cmd
。用最简单的话来说,你执行:batch.cmd "
。也就是说,只有一个参数由一个 双引号 标记组成。或batch.cmd ab"cd
,或任何更复杂的东西,通常被描述为具有奇数个["
] 标记。您的语句:IF "%1."=="." GOTO MyLabel
将失败并导致批处理执行结束(崩溃),通常会出现错误:The syntax of the command is incorrect.
,因为 ["
] 标记无法匹配。【参考方案11】:
空字符串是一对double-quotes
/""
,我们可以只测试长度:
set ARG=%1
if not defined ARG goto nomore
set CHAR=%ARG:~2,1%
if defined CHAR goto goon
然后针对 double-quotes
测试它的 2 个字符:
if ^%ARG:~1,1% == ^" if ^%ARG:~0,1% == ^" goto blank
::else
goto goon
这是一个您可以使用的批处理脚本。我认为它正确地捕获了空字符串。
这只是一个例子,你只需要根据你的脚本自定义上面的2个(或3个?)步骤。
@echo off
if not "%OS%"=="Windows_NT" goto EOF
:: I guess we need enableExtensions, CMIIW
setLocal enableExtensions
set i=0
set script=%0
:LOOP
set /a i=%i%+1
set A1=%1
if not defined A1 goto nomore
:: Assumption:
:: Empty string is (exactly) a pair of double-quotes ("")
:: Step out if str length is more than 2
set C3=%A1:~2,1%
if defined C3 goto goon
:: Check the first and second char for double-quotes
:: Any characters will do fine since we test it *literally*
if ^%A1:~1,1% == ^" if ^%A1:~0,1% == ^" goto blank
goto goon
:goon
echo.args[%i%]: [%1]
shift
goto LOOP
:blank
echo.args[%i%]: [%1] is empty string
shift
goto LOOP
:nomore
echo.
echo.command line:
echo.%script% %*
:EOF
本次酷刑测试结果:
.test.bat :: "" ">"""bl" " "< "">" (")(") "" :: ""-" " "( )"">\>" ""
args[1]: [::]
args[2]: [""] is empty string
args[3]: [">"""bl" "]
args[4]: ["< "">"]
args[5]: [(")(")]
args[6]: [""] is empty string
args[7]: [::]
args[8]: [""-" "]
args[9]: ["( )"">\>"]
args[10]: [""] is empty string
command line:
.test.bat :: "" ">"""bl" " "< "">" (")(") "" :: ""-" " "( )"">\>" ""
【讨论】:
错了,空字符串不是带两个双引号的字符串""
空字符串是空字符串 `` 批量空变量是未定义变量。您可以定义,对于您的参数,外部引号将被删除,但字符串仍然为空,长度为 0
在这种情况下(win cmd 参数),你不能用任何其他方式表示一个空字符串,即使是在 unix shell 下同样为空的双单引号也是如此。
是的,""
也用于空字符串,但使用%~1
删除外部引号非常容易。没必要用这么复杂的方案
你说得对,我可能说得不恰当,它不仅适用于空字符串,而且是一种枚举参数的安全方法。 "%~1"==""
之类的其他方式将失败,并出现 "Long File Name".txt
之类的参数,这是一个有效的参数。 edit:而且绝对没有你说的那么复杂。上面只有 2 个步骤进行测试,其余的都是详细示例。
"if not defined ARG" 似乎工作得很好(我的变量不是来自命令行)【参考方案12】:
脚本 1:
输入(“删除引号.cmd”“这是一个测试”)
@ECHO OFF
REM Set "string" variable to "first" command line parameter
SET STRING=%1
REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%
REM IF %1 [or String] is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel
REM OR IF "." equals "." GOTO MyLabel
IF "%STRING%." == "." GOTO MyLabel
REM GOTO End of File
GOTO :EOF
:MyLabel
ECHO Welcome!
PAUSE
输出(没有,%1 不是空白、空或 NULL):
使用上述脚本 1 在不带任何参数的情况下运行 ("Remove Quotes.cmd")
输出(%1 为空白、空或 NULL):
Welcome!
Press any key to continue . . .
注意:如果您在IF ( ) ELSE ( )
语句中设置了一个变量,则在它退出“IF”语句之前,它对 DEFINED 不可用(除非启用“延迟变量扩展”;启用后使用感叹号“ !" 代替百分比 "%" 符号。
例如:
脚本 2:
输入(“删除引号.cmd”“这是一个测试”)
@ECHO OFF
SETLOCAL EnableDelayedExpansion
SET STRING=%0
IF 1==1 (
SET STRING=%1
ECHO String in IF Statement='%STRING%'
ECHO String in IF Statement [delayed expansion]='!STRING!'
)
ECHO String out of IF Statement='%STRING%'
REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%
ECHO String without Quotes=%STRING%
REM IF %1 is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel
REM GOTO End of File
GOTO :EOF
:MyLabel
ECHO Welcome!
ENDLOCAL
PAUSE
输出:
C:\Users\Test>"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd" "This is a Test"
String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'
String in IF Statement [delayed expansion]='"This is a Test"'
String out of IF Statement='"This is a Test"'
String without Quotes=This is a Test
C:\Users\Test>
注意:它还会从字符串中删除引号。
例如(使用脚本 1 或 2): C:\Users\Test\Documents\Batch Files>"Remove Quotes.cmd" "This is "a" Test"
输出(脚本 2):
String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'
String in IF Statement [delayed expansion]='"This is "a" Test"'
String out of IF Statement='"This is "a" Test"'
String without Quotes=This is a Test
在脚本 2 中不带任何参数执行(“Remove Quotes.cmd”):
输出:
Welcome!
Press any key to continue . . .
【讨论】:
【参考方案13】:总结一下:
set str=%~1
if not defined str ( echo Empty string )
如果 %1 为“”或“或为空,此代码将输出“空字符串”。将其添加到当前不正确的已接受答案中。
【讨论】:
【参考方案14】:我遇到了很多问题,网上有很多答案。大多数都适用于大多数事情,但总有一个角落案例会破坏每个案例。
如果它有引号它可能不起作用,如果它没有引号它可能会中断,如果 var 有空格,则语法错误,有些只适用于参数(而不是环境变量),其他技术允许一个空一组引号作为“定义”传递,一些更复杂的引号不会让你在之后链接else
。
这是一个我很满意的解决方案,如果你发现它不适用的角落案例,请告诉我。
:ifSet
if "%~1"=="" (Exit /B 1) else (Exit /B 0)
在您的脚本或它自己的.bat
中包含该子例程应该可以工作。
所以如果你想写(伪):
if (var)
then something
else somethingElse
你可以写:
(Call :ifSet %var% && (
Echo something
)) || (
Echo something else
)
它适用于我的所有测试:
(Call :ifSet && ECHO y) || ECHO n
(Call :ifSet a && ECHO y) || ECHO n
(Call :ifSet "" && ECHO y) || ECHO n
(Call :ifSet "a" && ECHO y) || ECHO n
(Call :ifSet "a a" && ECHO y) || ECHO n
回显n
、y
、n
、y
、y
更多示例:
只想查看if
? Call :ifSet %var% && Echo set
如果不是(只有其他)? Call :ifSet %var% || Echo set
检查传递的参数;工作正常。 Call :ifSet %1 && Echo set
不想阻塞你的脚本/复制代码,所以你把它放在它自己的ifSet.bat
中?没问题:((Call ifSet.bat %var%) && Echo set) || (Echo not set)
【讨论】:
找到一个案例;如果您尝试使用 else 语法的 if,并且 then 块中的最后一个命令失败,则 else 将执行:(Call ifSet.bat YES && (Echo true & Echo x | findstr y)) || Echo
, echos true
and false
实际上,如果这是一个问题,并且您可以处理额外的行,您可以通过自己调用ifSet
,然后使用If %errorlevel% EQU 0 (x) Else (y)
来缓解这种情况
接受的答案(使用方括号)在哪些情况下不起作用?你能解释一下 Exit /B 的作用吗
由于某种原因,当我使用set
变量(如[%bob%]
,仅适用于[%2]
之类的参数)时,我测试它崩溃了,但现在重新检查它是否有效。我想我现在对[]
的唯一抱怨是它允许空引号通过,而这不会(所以这取决于你的用例,真的)
/B
标志阻止整个批处理退出,仅退出子例程或call
'd 批处理。除非你问whole command 在做什么;它返回一个错误代码,让调用脚本知道子程序的结果(0
通过,1
失败),可通过答案中的布尔逻辑或通过上述 cmets 中的%errorlevel%
使用【参考方案15】:
使用!而不是 " 用于空字符串检查
@echo off
SET a=
SET b=Hello
IF !%a%! == !! echo String a is empty
IF !%b%! == !! echo String b is empty
【讨论】:
小费真的很糟糕。引号至少可以处理空格和特殊字符,但感叹号不能。当启用延迟扩展时,感叹号在这里变得非常讨厌【参考方案16】:This way looks correct:
if "%~1" == "" if [%1] == [] echo Argument 1 is really empty.
First filter (if "%~1" == "") из safe way to detect argument is empty or "".
Second filter (if [%1] == []) will skip "" argument.
Remember we have two kind of empty arguments : really empty (nothing) and empty quotes "".
We have to detect both.
Next code takes all arguments "as is" in variable args:
:GetArgs
set args=%1
:ParseArgs
shift /1
if "%~1" == "" if [%1] == [] goto :DoneArgs
set args=%args% %1
goto :ParseArgs
:DoneArgs
if not defined args echo No arguments
if defined args echo Aguments are: %args%
This code correctly process "normal" arguments (simple words, "multiword phrases" or "") with balanced quotes.
Quoted arguments can even contain special chars like "a & b".
But it is still can fail with "abnormal" expressions with unbalanced quotes (do not use them).
【讨论】:
但由于myBatch ^&
的语法错误而失败。顺便提一句。使用[]
是没用的,它们没有特殊含义,也逃不掉任何东西。【参考方案17】:
最简单的解决方案,由两行代码组成:
SET /A var02 = %var01% / 1
IF %ERRORLEVEL% NEQ 0 (ECHO Variable var01 is NOT EXIST)
【讨论】:
简单但错误。使用set "var01=User&Doc"
、set var01=---
或set var01=1 0 0
进行测试
你是对的。我的示例仅检查变量是否存在,而不检查变量是否为空。我误解了主题任务。【参考方案18】:
我刚出生不到一个月(尽管 8 年前有人问过)...我希望他/她现在已经超越了批处理文件。 ;-) 我以前一直这样做。不过,我不确定最终目标是什么。如果他/她像我一样懒惰,那么我的 go.bat 就可以处理这样的事情。 (见下文) 但是,1,如果您直接将输入用作命令,则 OP 中的命令可能无效。即,
"C:/Users/Me"
是一个无效的命令(或者如果您在不同的驱动器上曾经是)。你需要把它分成两部分。
C:
cd /Users/Me
还有,2,“已定义”或“未定义”是什么意思? GIGO。我使用默认值来捕获错误。如果输入没有被捕获,它会掉到帮助(或默认命令)。所以,没有输入不是错误。您可以尝试 cd 到输入并捕获错误(如果有)。 (好吧,使用 go" 下载(只有一个括号)被 DOS 捕获。(苛刻!))
cd "%1"
if %errorlevel% neq 0 goto :error
而且,3,引号只需要在路径周围,而不是命令。即,
"cd C:\Users"
除非您在不同的驱动器上,否则很糟糕(或过去习惯)。
cd "\Users"
功能齐全。
cd "\Users\Dr Whos infinite storage space"
如果路径中有空格,则可以使用。
@REM go.bat
@REM The @ sigh prevents echo on the current command
@REM The echo on/off turns on/off the echo command. Turn on for debugging
@REM You can't see this.
@echo off
if "help" == "%1" goto :help
if "c" == "%1" C:
if "c" == "%1" goto :done
if "d" == "%1" D:
if "d" == "%1" goto :done
if "home"=="%1" %homedrive%
if "home"=="%1" cd %homepath%
if "home"=="%1" if %errorlevel% neq 0 goto :error
if "home"=="%1" goto :done
if "docs" == "%1" goto :docs
@REM goto :help
echo Default command
cd %1
if %errorlevel% neq 0 goto :error
goto :done
:help
echo "Type go and a code for a location/directory
echo For example
echo go D
echo will change disks (D:)
echo go home
echo will change directories to the users home directory (%homepath%)
echo go pictures
echo will change directories to %homepath%\pictures
echo Notes
echo @ sigh prevents echo on the current command
echo The echo on/off turns on/off the echo command. Turn on for debugging
echo Paths (only) with folder names with spaces need to be inclosed in quotes (not the ommand)
goto :done
:docs
echo executing "%homedrive%%homepath%\Documents"
%homedrive%
cd "%homepath%\Documents"\test error\
if %errorlevel% neq 0 goto :error
goto :done
:error
echo Error: Input (%1 %2 %3 %4 %5 %6 %7 %8 %9) or command is invalid
echo go help for help
goto :done
:done
【讨论】:
cd
的 /d
切换是有原因的:cd /d "C:\Users\Me" (and the proper path delimeter for Windows is
`,而不是 /
)。
这是一个很长的帖子,但甚至没有尝试回答这个问题。这是关于如何检测空参数,而不是what could be a default behaviour for an empty argument
以上是关于测试批处理文件中参数是不是为空的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章