美文网首页
bat 脚本参数解析

bat 脚本参数解析

作者: 刘亚彬92 | 来源:发表于2020-06-19 17:02 被阅读0次

    在日常开发过程中,我们经常会写一些脚本来帮助我们实现部分自动化的功能。而在使用脚本的过程中,参数解析又是经常使用的功能。本文将介绍 windows 平台上 bat 脚本如何进行参数解析。

    1 参数的组成

    首先我们来看一下命令的组成,一个完成的命令由命令(command)、选项(option)和位置参数(position argument)组成。如 git checkout -b dev 命令中。git 为主命令(command),checkout 为子命令(sub-command),-b 为选项(option)而 dev 为位置参数(positional argument)。

    • 主命令和子命令统称为命令(command),是必不可少的一部分。有些复杂的命令会将命令分为主命令和子命令两个部分,如 git 命令、ros 命令、docker 命令等。但是对于大部分简单的应用一个主命令就够了。
    • 选项(option)是控制命令行为最常用的方式,一般一个选项都会有长选项和短选项两种方式。如 node -hnode --help。一般长命令由 -- 开始而短命令由 - 开始。虽然 windows 风格的选项是以 / 开始(如 rd /s /q my_dir),但是由于 linux 风格的选项更加通用,因此这里将使用 linux 风格的选项。有些选项可能需要指定值,选项的赋值方式一般有两种形式:
      • 选项 值,如 mysql --host localhost.
      • 选项=值,如 mysql --host=localhost.
    • 位置参数(positional argument)往往是命令中的必选参数。如 git 中的切换分支命令,你必须要指定一个分支,因此这里分支名就是一个必选参数。又比如打开文件命令,文件是必选项,因此文件应该是打开文件命令的一个位置参数。但是位置参数也不一定是必选的,在一些命令中,也有可能包含一些可选的位置参数。一般情况下,位置参数会放在命令的最后。由于位置参数的使用相对来说没有那么严格,因此在一些的命令中,都没有位置参数。比如 ls 命令。位置参数必须要在前面加上任何前导符,如 curl [options...] <url> 命令中,最后的 url 就是位置参数。

    2 示例说明

    介绍完参数的基本组成之后,接下来我们就开始设计 bat 的参数解析方式了。由于我们使用 bat 脚本往往不会实现太复杂的功能。因此这里设计的参数解析也有一些简化,这里并不会使用位置参数,需要位置参数的地方,我们可以使用必须选项来代替。这里的参数解析主要实现以下功能:

    • 选项包括长选项和短选项两种方式。
    • 选项包括需要赋值的选项和无需赋值的选项。
    • 选项参数无效的时候给出错误警告。

    3 示例代码

    @echo off
    set virtual_env=conan
    
    setlocal EnableDelayedExpansion
    
    set is_workon=0
    set valid_param=0
    set set_vir_env=0
    set set_force=0
    set set_help=0
    set force=0
    
    cd ..
    set pro_root=!cd!
    :loop
    if not "%1"=="" (
        set valid_param=0
    
        if "%1" == "--vir_env" set set_vir_env=1
        if "%1" == "-v" set set_vir_env=1
        if "!set_vir_env!"=="1" (
            if "%2"=="" (
                echo parameter not enough, virtual environment must be give.
                goto :end
            )
            set virtual_env=%2
            set valid_param=1
            shift
        )
    
        if "%1" == "--force" set set_force=1
        if "%1" == "-f" set set_force=1
        if "!set_force!"=="1" (
            set force=1
            set valid_param=1
        )
    
        if "%1" == "--help" set set_help=1
        if "%1" == "-h" set set_help=1
        if "!set_help!" == "1" (
            echo USAGE: %0 options.
            echo  options:
            echo    `--vir_env/-v value`:  set conan virtual environment to the value, default is 'conan'.
            echo    `--force/-f`:          overwrite exist package.
            echo    `--help/-h`:           print this message and exit.
            goto :end
        )
    
        if "!valid_param!" == "0" (
            echo "unknown options: %1, use `-h` to show all avaliable options."
            goto :end
        )
        shift
        goto :loop
    )
    
    CALL workon !virtual_env!
    set is_workon=1
    if exist "conan_builds" rd /q /s "conan_builds"
    mkdir conan_builds
    cd conan_builds
    
    REM build and install
    cmake -DCMAKE_INSTALL_PREFIX=%pro_root%/conan_install ..
    cmake --build . --config Release
    ctest -VV -C Release
    if errorlevel 1 (
        echo "ctest failed."
        goto :end
    )
    cmake --install . --config Release
    
    REM package
    cd !pro_root!/conan_pkg
    if "!force!"=="1" (
        conan export-pkg . common/dev --package-folder=!pro_root!/conan_install -f
    ) else (
        conan export-pkg . common/dev --package-folder=!pro_root!/conan_install
    )
    if errorlevel 1 (
        echo "package failed."
        goto :end
    )
    
    REM test
    cd !pro_root!/conan_pkg/pkg_test
    if exist "builds" rd /q /s "builds"
    mkdir builds
    cd builds
    conan install ..
    cmake ..
    cmake --build . --config Release
    bin\main.exe
    if errorlevel 1 (
        echo "package test failed."
        goto :end
    )
    
    :end
    if "!is_workon!" == "1" (
        CALL deactivate
    )
    cd !pro_root!/scripts
    
    

    这个示例代码是用来实现 c++ 库的自动编译、测试、打包、测试包的流程。由于这里我们主要是学习如何使用 bat 的参数解析。因此具体的执行内容其实我们不用关心。这里一共使用了三个参数:

    • -v, --vir_env 用来指定 python 的虚拟环境名称。这是一个带值的选项。这里注意获取到值时,需要额外执行一次 shift
    • -f, --force 如果之前已经打包过相同的包了,是否覆盖之前的包。这是一个不带值的选项。
    • -h, --help 用来显示帮助信息。

    在输入其他无效的选项时,会报错。这里在实现的时候需要注意一下几点:

    • 由于 bat 脚本的 if 语句中,无法实现两个条件的“或”运算,所以这里使用两个 if 语句来分别判断一个选项的长短形式,同时还使用了一个中间变量保存设置结果。
    • 部分变量的引用使用 !变量! 的形式,而不是 %变量% 的形式。这是为了保证这些变量能够延后解析。如果使用 %变量% 来引用变量,这些变量并不会随着我们的赋值而改变。同时需要注意的是 !变量! 的引用形式需要声明 setlocal EnableDelayedExpansion
    • bat 脚本在执行命令的时候并不会因为命令执行出错而停止。因此我们需要通过判断 errorlevel 这个变量来判断之前的一个命令是否执行成功,如果执行失败可以选择退出脚本。

    其他的语句要么比较容易理解,或者是和业务相关无需关心,因此这里不再介绍了。

    参考资料:

    windows batch SET inside IF not working
    How do I get the application exit code from a Windows command line?
    Windows Bat file optional argument parsing
    How to use logical "OR" operator in batch script

    相关文章

      网友评论

          本文标题:bat 脚本参数解析

          本文链接:https://www.haomeiwen.com/subject/majpxktx.html