在批处理文件中测试参数是否为空的正确方法是什么?

我需要测试是否设置了一个变量。我已经尝试了几种技术,但每当%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.

根据这个网站,这些是支持的IF语法类型。所以,我不知道该怎么做。

IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command

更新:在2020-10-25,我更新了接受的答案,从使用括号到使用波浪号。每个人都说波浪更好,因为它更安全。我有点撕裂,因为波浪线看起来更复杂,不太清楚它的目的是什么,但尽管如此,我改变了它。

446762 次浏览

用方括号代替引号:

IF [%1] == [] GOTO MyLabel

括号是不安全的:只使用方括号。

我通常用这个:

IF "%1."=="." GOTO MyLabel

如果%1为空,If将比较"."和".",结果为真。

你可以使用:

IF "%~1" == "" GOTO MyLabel

去掉外部的引号。一般来说,这是一种比使用方括号更可靠的方法,因为即使变量中有空格,它也能工作。

从IF /?:

如果命令扩展项已启用If 修改如下:

IF [/I] string1 compare-op string2 command
IF CMDEXTVERSION number command
IF DEFINED variable command

......

DEFINED条件刚好 像EXISTS一样,除了它需要一个 环境变量名称和返回值 如果环境变量为,则为 定义。< / p >

脚本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):


使用上面的脚本运行("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 \批处理文件>"删除引号。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 . . .

最好的半解决方案之一是将%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和有""%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%防弹获取内容,你可以读取如何接收最奇怪的命令行参数?

使用“IF DEFINED变量命令”测试批处理文件中的变量。

但如果您想测试批处理参数,请尝试以下代码以避免棘手的输入(如“1 2”或ab^>cd)

set tmp="%1"
if "%tmp:"=.%"==".." (
echo empty
) else (
echo not empty
)
我对网上的很多答案都有很多问题。大多数都适用于大多数情况,但总有一个极端情况会破坏每一个 如果有引号它可能不起作用,如果没有引号它可能会中断,如果var有空格则会出现语法错误,有些只对参数有效(而不是环境变量),其他技术允许将空引号集作为“defined”传递,而一些更棘手的技术不允许在后面链接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

回显nynyy


更多的例子:

  • 想检查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)

我根据这里的答案创建了这个小批处理脚本,因为有很多有效的答案。只要遵循相同的格式,可以随意添加:

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

空字符串是一对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" " "< "">"  (")(") "" :: ""-"  " "( )"">\>" ""

总结一下:

set str=%~1
if not defined str ( echo Empty string )

如果%1为“”或“”或为空,此代码将输出“空字符串”。将其添加到目前不正确的公认答案中。

使用!而不是“空字符串检查”

@echo off
SET a=
SET b=Hello
IF !%a%! == !! echo String a is empty
IF !%b%! == !! echo String b is empty

你可以使用

if defined (variable) echo That's defined!
if not defined (variable) echo Nope. Undefined.

我测试下面的代码,它是好的。

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

我在不到一个月的时间里就被录取了(尽管这是8年前的要求)…我希望他/她现在已经超越批处理文件了。;-) 我以前经常这么做。但我不确定最终目标是什么。如果他/她像我一样懒,我的go.bat就能解决这些问题。(见下文) 但是,1,如果您直接将输入作为命令使用,则OP中的命令可能无效。例如,< / p >

"C:/Users/Me"

是无效命令(如果您在不同的驱动器上,则过去是无效命令)。你得把它分成两部分。

C:
cd /Users/Me

第二,'defined'和'undefined'是什么意思?GIGO。我使用默认值来捕捉错误。如果输入没有被捕获,它将被删除以帮助(或默认命令)。所以,没有输入不是错误。您可以尝试cd到输入并捕捉错误(如果有的话)。(好的,使用go "downloads(只有一个括号)被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

不幸的是,我没有足够的声誉来评论或投票目前的答案,我不得不自己写。

最初OP的问题说的是“变量”而不是“参数”,这让人非常困惑,特别是因为这是谷歌中搜索如何测试空白变量的头号链接。自从我最初的答案以来,Stephan编辑了原始问题,以使用正确的术语,但我没有删除我的答案,而是决定留下它来帮助澄清任何困惑,特别是在谷歌仍然派人来这里寻找变量的情况下:

%1不是变量!它是一个命令行参数。

非常重要的区别。后面带数字的单个百分号表示命令行参数,而不是变量。

使用set命令设置变量,并使用2%符号(一个在前面,一个在后面)回收变量。例如%myvar%

要测试空变量,您可以使用“if not defined”语法(显式变量命令不需要任何百分号),例如:

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的答案。)

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

最简单的解决方案,由两行代码组成:

SET /A var02 = %var01% / 1
IF %ERRORLEVEL% NEQ 0 (ECHO Variable var01 is NOT EXIST)