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

201

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

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


如何将命令行参数传递给批处理文件:https://dev59.com/xHVD5IYBdhLWcg3wTJrF - Eric Leschinski
5个回答

343

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

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

除了简单地访问这些参数之外,还有许多重要的技术需要注意。

检查是否传递了参数

这可以通过类似于IF "%~1"==""的结构来完成,当且仅当根本没有传递任何参数时,它是真实的。请注意波浪线字符,它会导致删除值为%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 /? 来查看所有这些功能的完整范围。


6
":parse, :endparse" 结构非常美妙,即使使用GOTO也不例外。谢谢!(我的意思是DOS-BASIC中被迫使用的GOTO)" - mmrtnt
1
当从powershell调用BAT时,这种技术可能会失败。像"name=John"这样的带引号的参数在执行期间会变成name John。解决方法是用单引号括起来,'"name=John"' - cmcginty
1
我怎么能这么长时间没有使用 CALL /? 呢?!我一直在用 Google 瞎搞。 - bigtlb
@Jon 我写了一个批处理文件,只包含一行代码 echo %1。如果我通过 cmd 调用它,例如 xx.bat &parameter > "C:\yy.txt",就会调用带参数的 bat 文件并将其写入 txt 文件,但是如果我在参数的开头或结尾加上 &,它就无法正常工作。其他文本都可以正常工作。 - Alex Mathew

64

使用批处理文件中的参数:%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.

命令行传入的参数必须是由空格分隔的字母数字字符。在DOS中,由于%0表示程序名称,如果在启动时运行AUTOEXEC.BAT文件,则%0将为空。

示例:

在名为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

16

@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://dev59.com/xHVD5IYBdhLWcg3wTJrF#50653047 上发布的类似帖子,其中我提供了更多分析逻辑的内容,以及我为什么使用某些结构。

很恶心。我今天不得不学习大部分内容,感到很痛苦。


5

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

如果您有Hello.bat,并且内容如下:

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

如果您通过命令调用批处理程序,需要使用以下命令:

hello.bat APerson241 %date%

您将会收到以下回复:

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


2

使用变量,即 .BAT 变量,并调用 %0%9


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