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

时间:2010-03-29 22:46:36

标签: windows shell batch-file cmd

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

16 个答案:

答案 0 :(得分:247)

使用方括号代替引号:

IF [%1] == [] GOTO MyLabel

括号不安全:仅使用方括号。

答案 1 :(得分:124)

您可以使用:

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

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

答案 2 :(得分:31)

最好的半解决方案之一是将%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 "&"^&

如果你想成为99%防弹,你可以阅读How to receive even the strangest command line parameters?

答案 3 :(得分:16)

从IF /?:

  

如果启用了Command Extensions IF   变化如下:

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

...

     

DEFINED条件只是起作用   喜欢EXISTS,只需要一个   环境变量名称和返回   如果环境变量为true,则为true   定义

答案 4 :(得分:6)

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

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

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

答案 5 :(得分:5)

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

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

答案 6 :(得分:3)

我通常使用它:

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

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

答案 7 :(得分:3)

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

答案 8 :(得分:3)

您可以使用

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

答案 9 :(得分:3)

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

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

答案 10 :(得分:2)

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

运行(“删除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&gt;“删除Quotes.cmd”“这是”一个“测试”

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

执行(“删除Quotes.cmd”)而不包含脚本2中的任何参数:

输出:

Welcome!

Press any key to continue . . .

答案 11 :(得分:2)

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

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

答案 12 :(得分:2)

总结一下:

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

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

答案 13 :(得分: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

Echo'd 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)

答案 14 :(得分:0)

使用!而不是&#34;用于空字符串检查

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

答案 15 :(得分:0)

我在不到一个月的时间里就进来了(尽管8年前被问过)...我希望他/她现在已经超越了批处理文件。 ;-) 我曾经一直这样做。不过,我不确定最终目标是什么。如果他/她像我一样懒,我的go.bat适用于那样的东西。 (见下文) 但是,1,如果您直接将输入用作命令,则OP中的命令可能无效。即,

"C:/Users/Me"

是一个无效的命令(或者如果您在不同的驱动器上,则会使用该命令)。你需要将它分成两部分。

C:
cd /Users/Me

而且,2,&#39;定义了什么&#39;或者&#39; undefined&#39;意思? GIGO。我使用默认值来捕获错误。如果输入没有被捕获,它将下降到帮助(或默认命令)。所以,没有输入不是错误。您可以尝试cd到输入并捕获错误(如果有)。 (好吧,使用go&#34;下载(只有一个paren)被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