如何在启动/调用批处理文件时检查参数是否已定义?

117

我正在尝试在批处理文件中使用以下验证逻辑,但即使未向批处理文件提供任何参数,“usage”块也不会执行。

if ("%1"=="") goto usage

@echo This should not execute

@echo Done.
goto :eof

:usage
@echo Usage: %0 <EnvironmentName>
exit 1

我做错了什么?


1
@double-beep - 这里的问题(由daniel-fortunov提出)是在你所提到的问题发布之前一年就已经被问过了。哪一个是(可能的)重复问题? - Kevin Fegan
1
@KevinFegan 因为另一个问题有更多的浏览量和更多的答案。 - double-beep
8个回答

185
命令行参数是否已设置的检查可以使用[%1]==[],但正如Dave Costa 指出的那样,"%1"==""也可以使用。
我还修复了用于转义大于号和小于号的语法错误。此外,exit需要一个/B参数,否则CMD.exe将退出。
@echo off

if [%1]==[] goto usage
@echo This should not execute
@echo Done.
goto :eof
:usage
@echo Usage: %0 ^<EnvironmentName^>
exit /B 1

26
[%1]==[]比起"%1"==""来说更好,因为它能正确处理%1本身包含双引号的情况。"%1"==""会出现“unexpected at this time”(此时无法预料)的错误信息。 - tekumara
2
请注意,如果您没有使用命令行参数而是使用“set”变量(我不知道正确的批处理术语),您可能希望使用"%myvar%"=="",因为如果myvar中有空格并且未加引号,则会收到“此时出现意外”的消息。 - Pat
1
@Pat SET 变量可以使用 IF NOT DEFINED VarName 块进行检查。此外,向 tukushan 加 1,因为他在比较中没有使用引号。只是不要这样做。永远不要。 - Fr0sT
12
"%~1"==""也可以运行,并且处理了%1带有双引号的情况。 - Drakkim
10
"%~1"=="" 处理变量中的空格,而 [] 版本则不处理。 - Okkenator

28
更高级的例子:
⍟ 无限参数。
⍟ 存在于文件系统中(是文件还是目录?)或通用字符串。
⍟ 指定是否为文件。
⍟ 指定是否为目录。
⍟ 没有扩展名,可以在旧脚本中使用!
⍟ 最小化代码 ☺
@echo off
:loop ::-------------------------- 是否有参数? if ["%~1"]==[""] ( echo 完成。 goto end ) ::-------------------------- 参数是否存在? if not exist %~s1 ( echo 不存在。 ) else ( echo 存在。 if exist %~s1\NUL ( echo 是一个目录。 ) else ( echo 是一个文件。 ) ) ::-------------------------- shift goto loop :end pause ✨ 其他内容..✨
■ 在 %~1 中 - ~ 去除任何包装的 "'

■ 在 %~s1 中 - s 使路径成为 DOS 8.3 命名,这是一个很好的技巧,可以在检查文件时避免文件名中的空格(这样就不需要用更多的 " 包装资源)。

["%~1"]==[""] "不能确定"参数是文件/目录还是通用字符串,因此表达式使用括号和原始未修改的 %1(如果有的话,只需去掉 " 包装即可)。

如果没有参数或者我们使用了 shift 并且参数列表指针已经超过了最后一个参数,则该表达式将被评估为 [""]==[""]

■ 这是您可以在不使用更多技巧的情况下具体化的程度(即使在 Windows 95 的批处理脚本中也可以工作...)

■ 执行示例

将其保存为 identifier.cmd

它可以识别无限数量的参数(通常你只能使用%1-%9),只需记得用引号包装参数,或使用8.3命名,或将它们拖放到上面(它会自动执行上述任一操作)。


这将使您能够运行以下命令:

identifier.cmd c:\ windows 并获取

存在
是一个目录
完成

identifier.cmd "c:\Program Files (x86)\Microsoft Office\OFFICE11\WINWORD.EXE" 并获取

存在
是一个文件
完成

⓷和多个参数(当然这就是全部内容...)

identifier.cmd c:\windows\system32 c:\hiberfil.sys "c:\pagefile.sys" hello-world

并且要得到

存在
是一个目录
存在
是一个文件
存在
是一个文件
不存在
完成。

自然地,它可能会更加复杂,但好的例子总是简单而最小化的。 :)

希望能对任何人有所帮助 :)

在此发布:CMD Ninja - 无限参数处理,识别文件系统中是否存在,识别文件或目录

这里有一个可行的示例,它接受任意数量的APK文件(Android应用程序),并通过调试控制台(ADB.exe)将它们安装在您的设备上: 使前面的帖子成为大规模APK安装程序,不使用ADB Install-Multi语法


CMD Ninja的链接对我无效,但是存档版本有效。顺便说一句,总结得非常好! - Sz.
你可以直接使用 :eof,这样就不需要标签了。它是隐式的。https://ss64.com/nt/goto.html - JGFMK

16

去掉括号。

样例批处理文件:

echo "%1"

if ("%1"=="") echo match1

if "%1"=="" echo match2

运行上述脚本的输出:

C:\>echo "" 
""

C:\>if ("" == "") echo match1 

C:\>if "" == "" echo match2 
match2

我认为实际上它将括号视为字符串的一部分,并进行比较。


1
if "%1"=="" will crash if the arg has spaces. For example: run.bat "a b". @amr has the best answer to use if "%~1"=="" - wisbucky

6
IF "%~1"=="" GOTO :Usage

如果%1本身被引用,则~将去除%1的引号。

" "将保护传递的特殊字符。例如,使用&ping调用脚本。


1
这是最佳答案。其他答案适用于某些情况,但对于更特殊的情况,如 run.bat "a b",将会失败。 - wisbucky
@wisbucky,这似乎不会影响被接受的答案。我错过了什么吗? - ruffin
@ruffin,例如:run.bat ""将不会被[%1]==[]捕获。 - wisbucky

4
这与其他答案相同,但只使用一个标签,并将用法放在首位,这还可以作为脚本的一种文档注释,通常放在顶部:
@echo off
:: add other test for the arguments here...
if not [%1]==[] goto main
:: --------------------------
echo This command does something.
echo.
echo %0 param%%1 param%%2
echo       param%%1 the file to operate on
echo       param%%1 another file

:: --------------------------
exit /B 1

:main
:: --------------------------
echo do something with all arguments (%%* == %*) here...

然而,如果您不必使用cmd/batch,则可以使用WSL上的bash或powershell,它们具有更合理的语法和较少的神秘功能。


1
IF "%1"=="" GOTO :Continue
.....
.....
:Continue
IF "%1"=="" echo No Parameter given

这个程序在运行 run.bat "a b" 时会崩溃。 - wisbucky

0

IF "%1"=="" 会失败,在某些有毒字符的情况下,所有版本都会失败。 只有 IF DEFINED 或 IF NOT DEFINED 是安全的。


1
if [not] defined ... 不能与 %1 这样的参数一起使用。你有例子吗,其中 if "%~1" ... 不起作用? - Stephan
这是一个简单的代码注入示例。创建一个名为unsafe.bat的文件,内容为if "%~1"=="" ( echo hello )。现在从Powershell运行以下命令:.\unsafe.bat "_`" neq `"`" echo Pwned &::"。同时使用社区答案https://dev59.com/AnRA5IYBdhLWcg3wyBD1#34552964运行相同的Powershell参数。您会发现批处理参数默认情况下非常不安全。 - Simon Streicher

0
你可以使用多行if语句。"if not defined 1"没有起作用。
if "%1"=="" (
  echo Usage:   ApplyImage WimFileName 
  exit 1
)

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