在Windows命令行中在批处理文件中使用参数


161

在Windows中,如何访问运行批处理文件时传递的参数?

例如,假设我有一个名为的程序hello.bat。当我hello -a在Windows命令行中输入时,如何让我的程序知道它-a作为参数传入?


如何通过命令行参数的批处理文件:stackoverflow.com/questions/26551/...
埃里克Leschinski

3
他提到“ DOS命令行”。
David R Tribble 2013年

Answers:


287

正如其他人已经说过的那样,可以在批处理文件中使用标记%1为来访问通过命令行传递的参数%9。您还可以使用其他两个令牌:

  • %0命令行中指定的可执行文件(批处理文件)名称
  • %*在命令行中指定的所有参数 -如果要将参数转发到另一个程序,这非常有用。

除了简单地如何访问参数外,还有许多重要的技术要注意。

检查是否传递了参数

这是通过类似的构造完成的,IF "%~1"==""当且仅当根本没有传递任何参数时,才为true。请注意,代字号字符会导致将所有引号从的值中删除%1;没有波浪号,如果该值包含双引号,则可能会得到意外的结果,包括语法错误的可能性。

处理9个以上的论点(或使生活更轻松)

如果需要访问9个以上的参数,则必须使用命令SHIFT。此命令将所有参数的值移动一位,因此%0取值%1%1取值的值%2,等等。%9取第十个参数的值(如果存在),该参数在调用前无法通过任何变量使用SHIFT(输入命令SHIFT /?以获取更多选项)。

SHIFT当您想轻松处理参数而不要求它们以特定顺序显示时,此功能也很有用。例如,一个脚本可以识别标志-a,并-b以任意顺序。在这种情况下,解析命令行的一种好方法是

:parse
IF "%~1"=="" GOTO endparse
IF "%~1"=="-a" REM do something
IF "%~1"=="-b" REM do something else
SHIFT
GOTO parse
:endparse
REM ready for action!

这种方案使您可以分析非常复杂的命令行而不会发疯。

替代批次参数

对于表示文件名的参数,shell提供了许多与处理文件相关的功能,这些功能无法通过其他任何方式访问。可使用以开头的结构访问此功能%~

例如,要获取作为参数传入的文件的大小,请使用

ECHO %~z1

要获取从中启动批处理文件的目录的路径(非常有用!),您可以使用

ECHO %~dp0

您可以通过CALL /?在命令提示符下键入来查看所有这些功能。


4
:parse,:endparse构造即使使用GOTO也很漂亮。谢谢!(我的意思是,DOS-BASIC强制执行GOTO)
mmrtnt 2013年

1
从Powershell调用BAT时,此技术可能会失败。像在exe期间"name=John"会变成带引号的参数name John。一种解决方法是用单引号引起来'"name=John"'
cmcginty

1
没有CALL /?!我怎么走了这么久?在这里,我一直都在与Google交流。
bigtlb

@Jon我写了一个蝙蝠文件,如果我通过cmd调用它只包含一个代码回显%1,例如xx.bat&parameter>“ C:\ yy.txt”用参数调用bat文件并写入txt文件,但是如果我给&在开头或结尾的参数中不起作用。任何其他文字都可以正常工作。
亚历克斯·马修

56

在批处理文件中使用参数:%0和%9

批处理文件可以参考通过与令牌参数的话:%0%9

%0 is the program name as it was called.
%1 is the first command line parameter
%2 is the second command line parameter
and so on till %9.

命令行中传递的参数必须为字母数字字符,并以空格分隔。由于%0是程序名称,因此%0在引导时启动DOS 中的AUTOEXEC.BAT将为空。

例:

将以下命令放在名为的批处理文件中mybatch.bat

@echo off
@echo hello %1 %2
pause

像这样调用批处理文件:mybatch john billy将输出:

hello john billy

为批处理文件获取9个以上的参数,请使用:%*

星号百分比令牌%*表示“其余参数”。您可以使用for循环来抓取它们,如下所示:

http://www.robvanderwoude.com/parameters.php

有关批处理参数定界符的说明

批处理文件会忽略命令行参数中的某些字符,具体取决于DOS版本,是否“转义”了它们,并且通常取决于它们在命令行中的位置:

commas (",") are replaced by spaces, unless they are part of a string in 
double quotes

semicolons (";") are replaced by spaces, unless they are part of a string in 
double quotes

"=" characters are sometimes replaced by spaces, not if they are part of a 
string in double quotes

the first forward slash ("/") is replaced by a space only if it immediately 
follows the command, without a leading space

multiple spaces are replaced by a single space, unless they are part of a 
string in double quotes

tabs are replaced by a single space

leading spaces before the first command line argument are ignored

5

批处理文件会在程序之后自动传递文本,只要它们是要分配给它们的变量即可。它们按照发送的顺序传递。例如,%1将是调用程序后发送的第一个字符串,等等。

如果您有Hello.bat,则内容为:

@echo off
echo.Hello, %1 thanks for running this batch file (%2)
pause

然后您通过以下命令调用批处理中的命令

hello.bat APerson241%date%

您应该会收到此消息:

您好,APerson241感谢您运行此批处理文件(01/11/2013)


4

@Jon的:parse/ :endparse计划是一个不错的开始,他对初次通过表示感谢,但是如果您认为Windows折磨的批处理系统会让您如此轻松……那么,我的朋友,您一定会感到震惊。我花了整整一整天的时间来进行这项艰苦的工作,经过大量痛苦的研究和实验,我终于找到了对现实生活实用程序可行的方法。

让我们说我们要实现一个实用程序foobar。它需要一个初始命令。它具有一个可选参数--foo,该参数带有一个可选值(当然不能为另一个参数)。如果缺少该值,则默认为default。它还具有一个可选参数--bar,该参数采用必需的值。最后,它可以--baz带有一个不允许值的标志。哦,这些参数可以按任何顺序排列。

换句话说,它看起来像这样:

foobar <command> [--foo [<fooval>]] [--bar <barval>] [--baz]

复杂?不,这在现实生活中似乎很典型。(git有人吗?)

事不宜迟,这里是一个解决方案:

@ECHO OFF
SETLOCAL
REM FooBar parameter demo
REM By Garret Wilson

SET CMD=%~1

IF "%CMD%" == "" (
  GOTO usage
)
SET FOO=
SET DEFAULT_FOO=default
SET BAR=
SET BAZ=

SHIFT
:args
SET PARAM=%~1
SET ARG=%~2
IF "%PARAM%" == "--foo" (
  SHIFT
  IF NOT "%ARG%" == "" (
    IF NOT "%ARG:~0,2%" == "--" (
      SET FOO=%ARG%
      SHIFT
    ) ELSE (
      SET FOO=%DEFAULT_FOO%
    )
  ) ELSE (
    SET FOO=%DEFAULT_FOO%
  )
) ELSE IF "%PARAM%" == "--bar" (
  SHIFT
  IF NOT "%ARG%" == "" (
    SET BAR=%ARG%
    SHIFT
  ) ELSE (
    ECHO Missing bar value. 1>&2
    ECHO:
    GOTO usage
  )
) ELSE IF "%PARAM%" == "--baz" (
  SHIFT
  SET BAZ=true
) ELSE IF "%PARAM%" == "" (
  GOTO endargs
) ELSE (
  ECHO Unrecognized option %1. 1>&2
  ECHO:
  GOTO usage
)
GOTO args
:endargs

ECHO Command: %CMD%
IF NOT "%FOO%" == "" (
  ECHO Foo: %FOO%
)
IF NOT "%BAR%" == "" (
  ECHO Bar: %BAR%
)
IF "%BAZ%" == "true" (
  ECHO Baz
)

REM TODO do something with FOO, BAR, and/or BAZ
GOTO :eof

:usage
ECHO FooBar
ECHO Usage: foobar ^<command^> [--foo [^<fooval^>]] [--bar ^<barval^>] [--baz]
EXIT /B 1

是的,真的很糟糕。参见我在https://stackoverflow.com/a/50653047/421049上发表的类似文章,其中我提供了更多有关逻辑发生的情况以及为什么使用某些构造的分析。

可怕。我今天大部分必须学习。而且很痛。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.