简体   繁体   English

使用可变数量的参数调用批处理文件

[英]Call batch file with variable number of arguments

Basically, the script below can be used in three different ways: call foo 基本上,下面的脚本可以以三种不同的方式使用:call foo

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

I cannot guarantee that the path or the command does not have spaces. 我不能保证路径或命令没有空格。

When I use foo.bat for executing my subroutine ssh , then everything works. 当我使用foo.bat执行我的子程序ssh ,一切正常。 Instead, when I try to call my subroutines boot_up or halt , an error apprears: 相反,当我尝试调用我的子程序boot_uphalt ,会出现错误:

( was unexpected at this time.

But, if I add a third argument to boot_up or halt , then everything works again. 但是,如果我将第三个参数添加到boot_uphalt ,那么一切都会再次起作用。

So my question is, how do I manage call of batch files with variable lenght of arguments? 所以我的问题是,如何使用变量长度的参数来管理批处理文件的调用?

: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

The source of your error is ) else if "%1"=="ssh" if not %3=="" ( - When you don't pass a 3rd argument, your code expands to ) else if "halt"=="ssh" if not =="" ( , which is invalid syntax. The entire compound statement must have valid syntax, even the branches that don't fire. You must make sure the left side of the comparison has at least one character. Enclosing quotes are typically used, because they protect against poison characters like & and | , and token delimiters like space, comma, equal, tab. 你的错误的来源是) else if "%1"=="ssh" if not %3=="" ( - 当你没有传递第三个参数,你的代码扩展到) else if "halt"=="ssh" if not =="" ( ,这是无效的语法。整个复合语句必须具有有效的语法,即使是不触发的分支。您必须确保比较的左侧至少有一个字符。通常使用包含引号,因为它们可以防止像&|这样的毒字符,以及空格,逗号,等号,制表符等标记分隔符。

In general, you should use if "%~1"=="someValue" ... when doing comparisons with command line arguments. 通常,在使用命令行参数进行比较时,应使用if "%~1"=="someValue" ... The ~ removes any existing enclosing quotes, and then you explicitly add your own. ~删除任何现有的封闭引号,然后显式添加自己的引号。 It is important to first remove the quotes because you cannot anticipate whether the user added their own quotes or not. 首先删除引号非常重要,因为您无法预测用户是否添加了自己的引号。 A value like "this&that" could be passed in, so "%1" would expand to ""this&that"" , and the & would no longer be quoted. 可以传入像"this&that"的值,因此"%1"将扩展为""this&that"" ,并且将不再引用& "%~1" expands to the desired "this&that" . "%~1"扩展到所需的"this&that" This strategy is not fool proof, but it is about as good as it gets without doing crazy batch programming that you probably don't want to get into. 这个策略并不是万无一失的,但是如果不进行疯狂的批量编程 ,你可能不想进入这个策略。

So your fixed code should look like 所以你的固定代码应该是这样的

: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

you could pre-process your arguments to remove passed quotes as follows (I simplified your code to create an independent test) 您可以预先处理您的参数以删除传递的引号,如下所示(我简化了您的代码以创建一个独立的测试)

@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
  • if argument is empty, just leave it as-is 如果参数为空,则保持原样
  • if argument starts with quotes, just remove the first & last char 如果参数以引号开头,则只删除第一个和最后一个字符
  • use %ARGx% (quoted) from now on instead of %1 , %2 从现在开始使用%ARGx% (引用)代替%1%2

quick test using only argument 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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM