【问题标题】:Call batch file with variable number of arguments使用可变数量的参数调用批处理文件
【发布时间】:2017-04-02 02:41:50
【问题描述】:

基本上,下面的脚本可以以三种不同的方式使用: 调用 foo

  1. .bat boot_up "path"
  2. .bat halt "path"
  3. .bat ssh "path" "command"

我不能保证路径或命令没有空格。

当我使用 foo.bat 执行我的子例程 ssh 时,一切正常。相反,当我尝试调用我的子例程 boot_uphalt 时,会出现错误:

( was unexpected at this time.

但是,如果我向boot_uphalt 添加第三个参数,那么一切都会再次运行。

所以我的问题是,如何管理具有可变参数长度的批处理文件的调用?

:main
    echo Argument 1: (%1)
    echo Argument 2: (%2)
    echo Argument 3: (%3)

    call :set_cygwin_env || exit /b 1

    if not "%1"=="" if not %2=="" (
        if "%1"=="boot_up" (
            call :boot_up %2
        ) else if "%1"=="halt" (
            call :halt %2
        ) else if "%1"=="ssh" if not %3=="" (
            call :ssh %2 %3
        ) else (
            call :show_help || exit /b 1
        )
    ) else (
        call :show_help || exit /b 1
    )
:exit

【问题讨论】:

  • if not %3=="" => if not "%3"==""。你已经为第一个 arg 做到了...
  • 我把这两个引号放了,因为当我调用批处理文件时,我在“”之间传递了参数。
  • 你真的必须在引号之间传递它们吗?我的意思是没有空格,那有什么意义呢?
  • 我不能保证路径或命令没有空格。在 Windows 上,这很常见。
  • if not "%~3"=="" 是唯一可靠的方法(注意~ 修饰符)...

标签: windows batch-file command-line cmd command-line-arguments


【解决方案1】:

您的错误来源是) else if "%1"=="ssh" if not %3=="" ( - 如果您不传递第三个参数,您的代码将扩展为) else if "halt"=="ssh" if not =="" (,这是无效的语法。整个复合语句必须具有有效的语法,即使是不触发的分支。您必须确保比较的左侧至少有一个字符。通常使用封闭引号,因为它们可以防止像 &| 这样的有毒字符以及像空格、逗号、相等、制表符这样的标记分隔符。

一般来说,在与命令行参数进行比较时,您应该使用if "%~1"=="someValue" ...~ 删除任何现有的封闭引号,然后您明确添加自己的引号。首先删除引号很重要,因为您无法预测用户是否添加了自己的引号。可以传入像 "this&that" 这样的值,因此 "%1" 将扩展为 ""this&that"",而 & 将不再被引用。 "%~1" 扩展为所需的 "this&that"。这个策略不是万无一失的,但它与你可能不想进入的 crazy batch programming 一样好。

所以你的固定代码应该是这样的

:main
    echo Argument 1: (%1)
    echo Argument 2: (%2)
    echo Argument 3: (%3)

    call :set_cygwin_env || exit /b 1

    if not "%~1"=="" if not "%~2"=="" (
        if "%~1"=="boot_up" (
            call :boot_up %2
        ) else if "%~1"=="halt" (
            call :halt %2
        ) else if "%~1"=="ssh" if not "%~3"=="" (
            call :ssh %2 %3
        ) else (
            call :show_help || exit /b 1
        )
    ) else (
        call :show_help || exit /b 1
    )
:exit

【讨论】:

    【解决方案2】:

    您可以按如下方式预处理您的参数以删除传递的引号(我简化了您的代码以创建独立测试)

    @echo off
    
    :main    
        set ARG1=%1
        set ARG2=%2
        set ARG3=%3
    
        if x%ARG1%==x goto skarg1
        if ^%ARG1:~0,1%==^" set ARG1=%ARG1:~1,-1%
    :skarg1
        if x%ARG2%==x goto skarg2
        if ^%ARG2:~0,1%==^" set ARG2=%ARG2:~1,-1%
    :skarg2
        if x%ARG3%==x goto skarg3
        if ^%ARG3:~0,1%==^" set ARG3=%ARG3:~1,-1%
    :skarg3
    
        echo Argument 1: (%ARG1%)
        echo Argument 2: (%ARG2%)
        echo Argument 3: (%ARG3%)
    
            if "%ARG1%"=="boot_up" if not "%ARG2%"=="" (
                echo bootup "%ARG2%"
            )
    :exit
    
    • 如果参数为空,则保持原样
    • 如果参数以引号开头,只需删除第一个和最后一个字符
    • 从现在开始使用%ARGx%(引用)代替%1,%2

    仅使用参数 2 的快速测试:

    L:\>args boot_up
    Argument 1: (boot_up)
    Argument 2: ()
    Argument 3: ()
    L:\>args boot_up arg2
    Argument 1: (boot_up)
    Argument 2: (arg2)
    Argument 3: ()
    bootup "arg2"
    L:\>args boot_up "arg2 space"
    Argument 1: (boot_up)
    Argument 2: (arg2 space)
    Argument 3: ()
    bootup "arg2 space"
    L:\>args boot_up "arg2"
    Argument 1: (boot_up)
    Argument 2: (arg2)
    Argument 3: ()
    bootup "arg2"
    

    【讨论】:

    • 最好使用%~1 ...第一个参数,如果存在,则删除周围的双引号。在运行call /? 的命令提示符窗口中的命令 CALL 输出的帮助下进行了解释。
    猜你喜欢
    • 2020-06-05
    • 2021-03-16
    • 1970-01-01
    • 2015-12-19
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 2013-03-30
    • 2019-08-29
    相关资源
    最近更新 更多