在Windows批处理中检查空变量

69
我正在编写一个Windows批处理文件,将三个文本文件bcp到SQL Server中。如果在生产环境中出现问题,我希望能够覆盖文件名。因此,我考虑这样做。
bcp.exe MyDB..MyTable1 in %1 -SMyServer -T -c -m0
bcp.exe MyDB..MyTable2 in %2 -SMyServer -T -c -m0
bcp.exe MyDB..MyTable3 in %3 -SMyServer -T -c -m0

我希望能够为三个文件输入默认名称,以便在未提供位置参数时使用。想法是执行以下操作:
myjob.bat

可以不带参数执行,默认使用默认值,或者执行

myjob.bat "c:\myfile1" "c:\myfile2" "c:\myfile3"

并使其使用这些文件。我无法弄清楚如何判断%1、%2和%3是否存在或为空。我也不知道如何有条件地设置这些值。这可能吗?任何建议都将不胜感激。


任何有兴趣实现带有默认值的可选脚本参数的人都应该查看关于Windows批处理文件可选参数解析的问题的这个答案 - dbenham
5个回答

126
要测试命令行参数是否存在,请使用空括号:
IF [%1]==[] echo Value Missing

或者

IF [%1] EQU [] echo Value Missing

在这里,SS64关于IF的页面会对你有所帮助,可以查看“测试变量是否为空”部分。

你无法设置位置参数,所以你应该做的是像这样进行操作

SET MYVAR=%1

你可以根据MYVAR的内容重新设置它。

这是否意味着 IF "%1"=="" 不好? - bryc
是的,当arg1带有引号时,"%1"会生成语法错误,因此最好使用方括号。 - mosh
如果“%~1”为空,几乎总是最好的选择,不要使用“IF [%1]==[]”,因为它无法处理像“file with space.txt”和“Special&char”这样的内容。 - jeb
如果“%~1”为空,几乎总是最好的选择,不要使用“IF [%1]==[]”,因为它无法处理像“file with space.txt”和“Special&char”这样的内容。 - undefined

29

正确的方法是使用“if defined”语句,用于检测变量是否存在。例如:

IF DEFINED somevariable echo Value exists
在这种情况下,应该使用否定形式:
IF NOT DEFINED somevariable echo Value missing

注意:变量名应该不带“%”字符使用。


谢谢您的回答。这个方法适用于数字参数,就像我在示例中使用的那样,还是只适用于命名变量? - John M Gant
+1 因为这个代码即使 somevariable引号,也能正常工作,而 IF [%somevariable%]==[] 则会报错。 - Juan Antonio Tubío
@TerraAshley,不幸的是,这不能与%1一起使用。 - Ameen

28

两个答案都是正确的,但我做法略有不同。你可能需要考虑一些事情......

用以下内容开始批处理:

SetLocal

并以此结束

EndLocal

这将使得所有 'SETs' 只在当前会话中有效,并且不会留下任何类似于“FileName1”或任何其他你在运行期间设置的变量,这可能会干扰批处理文件的下一次运行。因此,你可以像这样做:

IF "%1"=="" SET FileName1=c:\file1.txt
另一个技巧是,如果您只提供了1个或2个参数,请使用SHIFT命令将它们移动,这样您要寻找的参数始终在%1处...例如,处理第一个参数,移动它们,然后再次进行。这样,您就不需要硬编码%1、%2、%3等内容了...Windows批处理器比人们想象的要强大得多。我曾经用它做过一些疯狂的事情,包括计算昨天的日期,甚至跨越月份和年份边界以及本地化等等。如果您真的想发挥创造力,可以在批处理器中调用函数...但那是另一种讨论方式...:)哦,而且也不要将批处理文件命名为.bat了...现在它们是.cmd文件了...呵呵...希望这能有所帮助。

谢谢您的建议。只是好奇...为什么要使用.cmd而不是.bat? - John M Gant
5
实际上,我认为这是一种回溯。BAT适用于DOS,CMD适用于WinNT。但是,真正的原因是,曾经有cmd.exe和command.com两个程序。.cmd与cmd.exe相关,它是这些程序的解析器。我认为这也会让你看起来更酷,但我无法确认。 :) - LarryF
1
它们之间有微妙的区别,Raymond Chen曾经在他的Old New Thing博客中写过这个问题,但我现在找不到了... Google并没有帮助我。另请参见此SO Q:https://dev59.com/questions/43VC5IYBdhLWcg3w51ny - RBerteig

13
rem set defaults:
set filename1="c:\file1.txt"
set filename2="c:\file2.txt"
set filename3="c:\file3.txt"
rem set parameters:
IF NOT "a%1"=="a" (set filename1="%1")
IF NOT "a%2"=="a" (set filename2="%2")
IF NOT "a%3"=="a" (set filename1="%3")
echo %filename1%, %filename2%, %filename3%

但要小心引号字符,因为在变量中可能需要它们,也可能不需要。


2
+1;几乎任何字符或字符串都可以:如果不是%1.==。如果不是{%1}=={}; 如果不是%1null==null... - Patrick Cuff

1
晚了一步回答,但目前被接受的答案至少是次优的。
使用引号始终比使用其他字符来包含%1更好。因为当%1包含空格或特殊字符(如&)时,IF [%1] ==会简单地停止并显示语法错误。
但是对于%1包含引号的情况,例如myBatch.bat "my file.txt",一个简单的IF "%1" == ""会失败。
但是,由于您无法知道是否使用了引号,因此有语法%~1,它在必要时删除封闭引号。
因此,代码应该如下所示:
set "file1=%~1"
IF "%~1"=="" set "file1=default file"

type "%file1%"   --- always enclose your variables in quotes

如果您需要处理类似 myBatch.bat "This & will "^&crash 的陌生和恶意参数,那么请查看SO:如何接收最奇怪的命令行参数?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接