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


213

我需要测试是否设置了变量。我已经尝试了几种技术,但他们忽视了,只要%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

1
在我的系统(Windows 2003和Windows 7)上,if "%1" == "" GOTO MyLabel只要%1双引号的偶数都不会致命地终止脚本的执行。我看到一个奇数的双引号%1终止了该脚本的执行,并出现以下错误:The syntax of the command is incorrect.使用方括号解决问题的以下解决方案已被标记为正确答案,但似乎并没有做得更好。当%1双引号的数量为奇数时,该解决方案也会因相同的错误而失败。
Susam Pal

@SusamPal有趣。尝试使用其下的括号版本,看看是否可行。那我测试了更多。我几天前刚刚更新了接受的答案。
blak3r

Dan Story的答案确实确实不错。我使用方括号使用该版本。
Susam Pal 2014年

一个很好的“全部捕获”示例:stackoverflow.com/questions/830565/…涵盖了文件/目录以及参数中的通用字符串/数字混合。

令人沮丧的是- IF DEFINED仅在环境变量而不是脚本变量上工作会浪费潜力!
kayleeFrye_onDeck

Answers:


290

使用方括号代替引号:

IF [%1] == [] GOTO MyLabel

括号不安全:只能使用方括号。


11
括号不安全!像&in中的内容%1将打破界限
jeb 2011年

14
只要在参数中没有空格,使用其他字符(例如if #%1#==##if [%1]==[])就可以了,否则会…was unexpected at this time出错。
Synetech

12
"%~1"正如我在回答中提到的,使用确实是更好的方法。
jamesdlin

8
伙计们,@ jamesdlin是正确的。如果变量文本带有空格或为,则此方法将不起作用==。请改用他的答案。
James Ko 2016年

4
您不清楚it DOES NOT work with spaces。请使用@jamesdlin答案。
JB。和莫妮卡。

153

您可以使用:

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

去除外部引号。通常,与使用方括号相比,这是一种更可靠的方法,因为即使变量中有空格也可以使用。


9
这确实是一个很好的方法。通过使用~,您可以除去外部引号(如果存在),然后手动将其重新添加(仅确保一组)。此外,如果参数包含空格,必须使用引号(当我以前的版本使用#or或方括号而不是引号引起带有空格的参数引发…was unexpected at this time错误时,我就学到了这很难的方法。)
Synetech

4
这是否也适用于%MYVAR%之类的常规变量,而不适用于%1之类的参数?
simpleuser

4
@simpleuser糟糕,您是对的,它不适用于一般环境变量。
jamesdlin

1
注意使用double'“'作为转义序列的字符串-尝试进行比较时脚本将崩溃。例如""this string will crash the comparison"",double'”'是正确的转义序列,并且如果double'“'进行替换将失败。字符串为空
Tydaeus

1
@Amalgovinus您可能可以将变量作为参数传递给子例程,然后让该子例程使用"%~1"
jamesdlin

38

最好的半解决方案之一是将其复制%1到变量中,然后使用延迟扩展(如delayExp)。对任何内容始终是安全的。

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%的防弹性能以获取内容,则可以阅读《如何接收最奇怪的命令行参数》?


18

从IF /?

如果启用了命令扩展,则IF更改如下:

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

......

DEFINED条件条件的工作方式与EXISTS相似,不同之处在于它采用环境变量名称,并且如果定义了环境变量,则返回true。


1
是的,我实际上尝试过这种方法,并且据我所知,这仅适用于环境变量。因此,不适用于%1或批处理文件中定义的变量。
blak3r

2
这仅适用于%1喜欢的人。实际上 “批处理文件中定义的变量” 是运行批处理文件时的环境变量,您可以IF DEFINED在它们上使用。
zb226 2013年

8

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

最初,OP的问题说的是“变量”而不是“参数”,这引起了很大的混乱,尤其是因为这是google中搜索如何测试空白变量的第一链接。自从我获得原始答案以来,Stephan已编辑了原始问题以使用正确的术语,但我决定删除该答案,以消除任何混乱,而不是删除我的答案,特别是在google仍派人来这里询问变量的情况下:

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


1
你是对的。但是正确的方法应该是仅将标题从if variable is empty更改为if parameter is empty。我刚刚做完。(冒使某些答案无效的风险,这些答案确实检查了变量而不是参数,因此无论如何都是无效的,因为他们没有回答问题)
Stephan

1
好的,谢谢斯蒂芬,没有意识到您可以做到这一点。我已经编辑了答案以反映更新。
AutoMattTick

6

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

但是,如果要测试批处理参数,请尝试以下代码,以避免输入麻烦(例如“ 1 2”或ab ^> cd)

set tmp="%1"
if "%tmp:"=.%"==".." (
    echo empty
) else (
    echo not empty
)

5

我用下面的代码测试,这很好。

@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是有原因的
jeb

4

我通常使用这个:

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

如果%1为空,则IF将比较“。” 至 ”。” 评估结果为true。


4
这是不正确的。这与以下内容相同:IF“%1” ==“”导致此帖子的原因是,如果%1本身具有引号,则此操作将失败。
blak3r 2010年

您是否要测试%1是否为空或是否带有引号?问题尚不清楚。如果在%1的命令行上未指定任何内容,我的答案将起作用。
Aphoria 2010年

>您是否要测试%1是否为空或是否带有引号? @aphoria,它必须能够同时处理这两种情况。
Synetech 2012年

我用它来算出是否已设置%1%,这对我来说很好。谢谢,好的答案!
查理

4

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

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

4

空字符串是一对double-quotes/ "",我们可以测试长度:

set ARG=%1
if not defined ARG goto nomore

set CHAR=%ARG:~2,1%
if defined CHAR goto goon

然后针对double-quotes以下两个字符进行测试:

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
jeb

在这种情况下(win cmd参数),您不能用任何其他方式来表示一个空字符串,甚至不能用双单引号将其表示为在unix shell下同样为空。
user6801759

是的,""也可以用于空字符串,但是%~1删除外引号非常容易。无需使用如此复杂的解决方案
jeb

您说对了,我可能会不正确地指出,它不仅适用于空字符串,而且是枚举参数的安全方法。诸如此类的其他方式"%~1"==""将失败,并带有诸如"Long File Name".txt有效参数之类的参数。编辑:绝对不是您所说的复杂。以上仅用于测试的2个步骤,其余均为详细示例。
user6801759 '16

“如果未定义ARG”似乎可以正常工作(我的变量不是来自命令行)
GrayFace


3

脚本1:

输入(“删除Quotes.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:

输入(“删除Quotes.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>“删除Quotes.cmd”“这是” a“测试”

输出(脚本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 . . .

3

总结一下:

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

如果%1是“”或“或为空,则此代码将输出” Empty string“。将其添加到当前不正确的已接受答案中。


0

我在网络上遇到了很多问题和很多答案。大多数工具都能完成大多数工作,但总有一个破例。
如果没有引号,它可能不起作用;如果没有引号,它可能会中断;如果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

回显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)

找到一个案例;如果您尝试使用if和else语法,并且then块中的最后一个命令失败,则else将执行:(Call ifSet.bat YES && (Echo true & Echo x | findstr y)) || Echotrue false
echos

实际上,如果这是一个问题,并且您可以处理一条额外的线路,则可以通过ifSetIf %errorlevel% EQU 0 (x) Else (y)
单独

在什么情况下接受的答案(使用方括号)不起作用?您能解释一下出口/ B的作用
吗?

由于某种原因,当我测试时,使用set变量(例如[%bob%],仅适用于[%2])时中断了,但是现在重新检查它是可行的。我想我[]现在唯一的困扰是它允许空引号通过,而这不会(所以实际上取决于您的用例)
Hashbrown

/B标志阻止整个批次退出,仅退出子例程或call'd批次。除非您问整个命令在做什么;它返回一个错误代码,以使调用脚本知道子例程的结果(0通过,1失败),可以通过答案中的布尔逻辑或通过%errorlevel%上面的注释来使用
Hashbrown

0

使用!代替“进行空字符串检查

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

1
提示确实不好。引号至少可以处理空格和特殊字符,而感叹号则不能。启用延迟扩展后,感叹号会变得非常讨厌
jeb

0

我进来的时间不到一个月(即使是8年前被问到的)……我希望他/她现在已经超出了批处理文件的范围。;-)我一直都这样做。不过,我不确定最终目标是什么。如果他/她像我这样懒惰,我的go.bat可以像这样工作。(请参见下文)但是,如果1直接将输入用作命令,则OP中的命令可能无效。即

"C:/Users/Me"

是无效的命令(或者曾经在其他驱动器上使用)。您需要将其分为两部分。

C:
cd /Users/Me

2,“定义”或“未定义”是什么意思?GIGO。我使用默认值来捕获错误。如果没有捕获到输入,它将丢弃以提供帮助(或默认命令)。因此,没有输入不是错误。您可以尝试cd到输入并捕获错误(如果有的话)。(好吧,使用DOS下载捕获了go(只有一个括号)。(严厉!))

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 `,未/)。
斯蒂芬
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.