ChatGPT解决这个技术问题 Extra ChatGPT

如何检查“.bat”文件中的命令行参数?

我的操作系统是 Windows Vista。我需要有一个“.bat”文件,我需要在其中检查用户是否输入了任何命令行参数。如果是,那么如果参数等于 -b,那么我会做一些事情,否则我会标记“无效输入”。如果用户没有输入任何命令行参数,那么我会做一些事情。我创建了以下 .bat 文件。它适用于 -b 且不等于 -b 的情况 - 但当用户未传递任何命令行参数时它会失败。

我总是得到错误:

GOTO was unexpected at this time.

谁能告诉我我在这里做错了什么?

ECHO OFF
CLS
ECHO.

IF [%1]==[/?] GOTO BLANK

IF %1=="-b" GOTO SPECIFIC

IF NOT %1=="-b" GOTO UNKNOWN

:SPECIFIC

ECHO SPECIFIC

GOTO DONE

:BLANK

ECHO No Parameter

GOTO DONE

:UNKNOWN

ECHO Unknown Option

GOTO DONE

:DONE

ECHO Done!
如果将括号(如在 GOTO BLANK 行中)添加到其他两个 IF 语句,是否可以解决问题?

S
Skip R

您需要检查参数是否为空:if "%~1"=="" goto blank

完成后,在 -b 上执行 if/else 开关:if "%~1"=="-b" (goto specific) else goto unknown

用引号将参数括起来可以更容易地检查诸如空白/空/缺少参数之类的内容。 "~" 确保双引号在命令行参数上时被去除。


这行得通!只有“else”不被接受。我收到错误:“else”不被识别为内部或外部命令、可运行程序或批处理文件。所以我为“不等于-b”的情况添加了另一个IF。感谢你及时的答复。
ELSE 必须与 IF 在同一行,或者必须直接在括号之后
如果 %1 包含空格,这似乎对我不起作用,如果它是可执行文件的完整路径,可能就是这种情况。请参阅 Jeremiah Willcock's answer,了解即使对于值中包含空格的参数也有效的解决方案。
如果您的论点是 File,它将不会被接受,在这种情况下,您应该只检查 existnot exist。这就是为什么你的论点应该定义明确,或者简单地使用 powershell 或 vbScript(如果你是 80 年代......)
run.bat "a b" 失败。如果 arg 有空格,"%1"=="" 会崩溃。请参阅stackoverflow.com/a/46942471
J
Jeremiah Willcock

查看 http://ss64.com/nt/if.html 以获得答案;命令是 IF [%1]==[] GOTO NO_ARGUMENT 或类似的。


这不仅有效!与 "%1"=="" 相比,它可以正常工作。我必须在我自己的答案中详细说明这一点。
这将在引用 %1 时中断,例如 foo.bat "1st parameter" 2nd_param。请参阅stackoverflow.com/questions/2541767/…
如果 arg 被引用,使用 [%1]==[-b] 将不匹配。示例 run.bat "-b"。请参阅stackoverflow.com/a/46942471
即使引用了论点,这也对我有用。例如 foo.bat "1st parameter" 在我的测试中运行良好。方括号似乎比 IF "%1"==""
T
Tomasz Gandor

简短的回答 - 使用方括号:

if [%1]==[] goto :blank

或(当您需要处理带引号的参数时,请参阅下面的编辑):

if [%~1]==[] goto :blank

为什么?你可能会问。好吧,正如 Jeremiah Willcock 提到的:http://ss64.com/nt/if.html - 他们使用它!好的,但是引号有什么问题?

同样,简短的回答:它们是“神奇的” - 有时双(双)引号会转换为单(双)引号。首先,他们需要匹配。

考虑这个小脚本:

@rem argq.bat
@echo off

:loop 
if "%1"=="" goto :done
echo %1
shift
goto :loop

:done
echo Done.

让我们测试一下:

C:\> argq bla bla
bla
bla
Done.

似乎工作。但是现在,让我们切换到二档:

C:\> argq "bla bla"
bla""=="" was unexpected at this time.

繁荣 这没有评估为真,也没有评估为假。剧本死了。如果你应该在某个地方关闭反应堆,那么 - 运气不好。你现在会像 Harry Daghlian 一样死去。

你可能会想——好吧,参数不能包含引号。如果他们这样做,就会发生这种情况。错了这里有一些安慰:

C:\> argq ""bla bla""
""bla
bla""
Done.

哦耶。别担心——有时这会奏效。

让我们尝试另一个脚本:

@rem args.bat
@echo off

:loop 
if [%1]==[] goto :done
echo %1
shift
goto :loop

:done
echo Done.

您可以测试自己,它适用于上述情况。这是合乎逻辑的——引号与括号无关,所以这里没有魔法。但是用括号给 args 加香料呢?

D:\>args ]bla bla[
]bla
bla[
Done.

D:\>args [bla bla]
[bla
bla]
Done.

那里没有运气。方括号不能阻塞 cmd.exe 的解析器。

让我们回到邪恶的名言片刻。问题就在那里,当论点以引用结束时:

D:\>argq "bla1 bla2"
bla2""=="" was unexpected at this time.

如果我只是通过怎么办:

D:\>argq bla2"
The syntax of the command is incorrect.

该脚本根本不会运行。 args.bat 相同:

D:\>args bla2"
The syntax of the command is incorrect.

但是,在这种情况下,当 " 字符“匹配”(即 - 是偶数)的数量时,我会得到什么:

D:\>args bla2" "bla3
bla2" "bla3
Done.

NICE - 我希望您了解 .bat 文件如何拆分它们的命令行参数(提示:*这与 bash 中的不完全一样)。上面的参数包含一个空格。但引号不会自动剥离。

和 argq?它对此有何反应?可以预见:

D:\>argq bla2" "bla3
"bla3"=="" was unexpected at this time.

所以 - 在你说之前想一想:“知道吗?只需使用引号。[因为,对我来说,这看起来更好]”。

编辑

最近,有关于这个答案的评论 - 好吧,方括号“无法处理”传递引用的参数并将它们视为没有被引用。

语法:

if "%~1"=="" (...)

不是双引号的一些新发现的优点,而是显示从参数变量中去除引号的简洁功能,如果第一个和最后一个字符是双引号。

这种“技术”同样适用于方括号:

if [%~1]==[] (...)

指出这一点很有用,所以我也赞成新的答案。

最后,双引号爱好者,您的书中是否存在 "" 形式的参数,还是空白?只是问';)


如果 arg 像 run.bat "-b" 一样被引用,方括号 [%1]==[-b] 将不匹配。请参阅stackoverflow.com/a/46942471
历史记录:对于 win 98 和更早的 MS/PC-DOS 系统批处理脚本,[%1]==[-b]"%1"=="-b" 是相同的。由于 win 2000/NT 引入了语法 if "%~1"=="-b",其中双引号具有特殊含义,这是您编写脚本的方式,因为它提供了更强大的保护。双引号会转义特殊字符的含义(在命令行中尝试 & | 和 % 字符)。 99.9% 的示例使用双引号语法 - 您的示例 argq bla2" "bla3 仅用于证明方括号的合理性。嵌入式双引号是灾难的秘诀 - 只是说'
@SkipR - 这就是为什么在 Windows 的文件系统中,您不能在名称中包含这些特殊字符。我没有数学证明,但我认为在 cmd 外壳中根本不能引用所有内容(在 - 通过一些转义序列等逐字记录的意义上)。在其他系统中,您有时可以引用所有内容,包括 NUL 字符。 (stackoverflow.com/questions/2730732/…) - 这个问题只是表明,您需要使用一些外部程序。
在 args 中使用等号失败,例如 "key=value"。我通过在变量(stackoverflow.com/a/51827258/2902367)中替换它们来解决这个问题,然后再检查它是否为空
P
PA.

除了我订阅的其他答案之外,您还可以考虑使用 IF 命令的 /I 开关。

... /I 开关(如果指定)表示进行不区分大小写的字符串比较。

如果您想为用户提供不区分大小写的灵活性来指定参数,这可能会有所帮助。

IF /I "%1"=="-b" GOTO SPECIFIC

J
Jeff Mercado

您正在比较字符串。如果省略参数,%1 将扩展为空白,因此命令变为 IF =="-b" GOTO SPECIFIC(例如,这是一个语法错误)。将字符串用引号(或方括号)括起来。

REM this is ok
IF [%1]==[/?] GOTO BLANK

REM I'd recommend using quotes exclusively
IF "%1"=="-b" GOTO SPECIFIC

IF NOT "%1"=="-b" GOTO UNKNOWN

IF [%1]==[/?] 不工作,但我做 IF [%1]==[] 或 "%1"=="",那么它工作。无论如何,我现在可以开始了。谢谢你快速的回复。
w
wisbucky

实际上,所有其他答案都有缺陷。最可靠的方法是:

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

详细说明:

如果使用空格和引号传递参数,使用 "%1"=="-b" 将彻底崩溃。这是最不可靠的方法。

IF "%1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "a b"

b""=="-b" was unexpected at this time.

使用 [%1]==[-b] 更好,因为它不会因空格和引号而崩溃,但如果参数被引号包围,它将不匹配。

IF [%1]==[-b] (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "-b"

(does not match, and jumps to UNKNOWN instead of SPECIFIC)

使用 "%~1"=="-b" 是最可靠的。 %~1 将去掉周围的引号(如果存在)。所以它可以带引号和不带引号,也可以不带参数。

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat
C:\> run.bat -b
C:\> run.bat "-b"
C:\> run.bat "a b"

(all of the above tests work correctly)

这不是方括号的结尾,您会看到:IF [%~1]==[] - 这有效,它甚至可以处理 "-b"。您只需要能够盒子、erm、方[括号]中思考。
D
D.Barev

我最近一直在努力在批处理文件中实现复杂的参数切换,所以这是我的研究结果。提供的答案都不是完全安全的,例如:

如果参数包含在引号中(文件名等需要),则 "%1"=="-?" 将不匹配,或者如果参数包含在引号中且包含空格(在文件名中也经常出现),则 "%1"=="-?" 将崩溃

@ECHO OFF
SETLOCAL
echo.
echo starting parameter test...
echo.
rem echo First parameter is %1
if "%1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)
C:\>test.bat -?

starting parameter test...

Condition is true, param=-?

C:\>test.bat "-?"

starting parameter test...

Condition is false, param="-?"

如果参数在引号中包含空格,则任何带有方括号 [%1]==[-?][%~1]==[-?] 的组合都将失败:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if [%~1]==[-?] (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat "long file name"

starting parameter test...

First parameter is "long file name"
file was unexpected at this time.

建议的最安全解决方案 "%~1"=="-?" 会因包含引号外文本和引号内带有空格的文本的复杂参数而崩溃:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if "%~1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat -source:"long file name"

starting parameter test...

First parameter is -source:"long file name"
file was unexpected at this time.

确保涵盖所有上述场景的唯一方法是使用 EnableDelayedExpansion 并使用变量通过引用(而不是通过值)传递参数。那么即使是最复杂的场景也能正常工作:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
echo.
echo starting parameter test...
echo.
echo First parameter is %1
:: we assign the parameter to a variable to pass by reference with delayed expansion
set "var1=%~1"
echo var1 is !var1!
:: we assign the value to compare with to a second variable to pass by reference with delayed expansion
set "var2=-source:"c:\app images"\image.png"
echo var2 is !var2!
if "!var1!"=="!var2!" (echo Condition is true, param=!var1!) else (echo Condition is false, param=!var1!)
C:\>test.bat -source:"c:\app images"\image.png

starting parameter test...

First parameter is -source:"c:\app images"\image.png
var1 is -source:"c:\app images"\image.png
var2 is -source:"c:\app images"\image.png
Condition is true, param=-source:"c:\app images"\image.png

C:\>test.bat -source:"c:\app images"\image1.png

starting parameter test...

First parameter is -source:"c:\app images"\image1.png
var1 is -source:"c:\app images"\image1.png
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images"\image1.png

C:\>test.bat -source:"c:\app images\image.png"

starting parameter test...

First parameter is -source:"c:\app images\image.png"
var1 is -source:"c:\app images\image.png"
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images\image.png"