我需要测试是否设置了一个变量。我尝试了几种技术,但每当%1被引号包围时,它们似乎都失败了,例如%1是“c:\一些带空格的路径”。
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,我更新了接受的答案,从使用括号到使用波浪号。每个人都说波浪更好,因为它更安全。我有点撕裂,因为波浪线看起来更复杂,不太清楚它的目的是什么,但尽管如此,我改变了它。
脚本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"这是"一个"测试"
输出(脚本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复制到一个变量中,然后使用延迟展开,如delayedxp。对于任何内容总是安全的。
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%防弹获取内容,你可以阅读如何接收甚至是最奇怪的命令行参数?
我对网上的很多答案都有很多问题。大多数都适用于大多数情况,但总有一个极端情况会破坏每一个。
如果有引号,它可能不起作用,如果没有引号,它可能会中断,如果var有空格,则会出现语法错误,有些只对参数有效(而不是环境变量),其他技术允许一个空引号集作为“defined”传递,还有一些更棘手的技术不允许随后链接else。
这是一个我很满意的解决方案,如果你发现它不起作用的极端情况,请告诉我。
:ifSet
if "%~1"=="" (Exit /B 1) else (Exit /B 0)
在你的脚本中或在它自己的.bat中拥有子例程应该可以工作。
所以如果你想写(在pseudo中):
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
更多的例子:
想看看是不是?调用:ifSet %var% && Echo set
如果不是(只有其他)呢?呼叫:ifSet %var% ||回声设置
检查传递的参数;工作很好。调用:ifSet %1 && Echo set
不想堵塞你的脚本/欺骗代码,所以你把它放在它自己的ifSet.bat?No problem:(调用ifSet.bat %var%) && Echo set) || (Echo未设置)
空字符串是一对双引号/"",我们可以直接测试长度:
set ARG=%1
if not defined ARG goto nomore
set CHAR=%ARG:~2,1%
if defined CHAR goto goon
然后用双引号测试它的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年前的要求)……我希望他/她现在已经超越批处理文件了。: -)
我以前经常这么做。但我不确定最终目标是什么。如果他/她像我一样懒,我的go.bat就能解决这些问题。(见下文)
但是,1,如果您直接将输入作为命令使用,则OP中的命令可能无效。也就是说,
"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的答案。)