bat 腳本參數(shù)解析

在日常開發(fā)過程中蹲缠,我們經(jīng)常會(huì)寫一些腳本來幫助我們實(shí)現(xiàn)部分自動(dòng)化的功能。而在使用腳本的過程中刊棕,參數(shù)解析又是經(jīng)常使用的功能察郁。本文將介紹 windows 平臺(tái)上 bat 腳本如何進(jìn)行參數(shù)解析。

1 參數(shù)的組成

首先我們來看一下命令的組成轩缤,一個(gè)完成的命令由命令(command)命迈、選項(xiàng)(option)和位置參數(shù)(position argument)組成。如 git checkout -b dev 命令中火的。git 為主命令(command)壶愤,checkout 為子命令(sub-command),-b 為選項(xiàng)(option)而 dev 為位置參數(shù)(positional argument)馏鹤。

  • 主命令和子命令統(tǒng)稱為命令(command)征椒,是必不可少的一部分。有些復(fù)雜的命令會(huì)將命令分為主命令和子命令兩個(gè)部分湃累,如 git 命令勃救、ros 命令、docker 命令等治力。但是對(duì)于大部分簡(jiǎn)單的應(yīng)用一個(gè)主命令就夠了蒙秒。
  • 選項(xiàng)(option)是控制命令行為最常用的方式,一般一個(gè)選項(xiàng)都會(huì)有長(zhǎng)選項(xiàng)和短選項(xiàng)兩種方式宵统。如 node -hnode --help晕讲。一般長(zhǎng)命令由 -- 開始而短命令由 - 開始。雖然 windows 風(fēng)格的選項(xiàng)是以 / 開始(如 rd /s /q my_dir),但是由于 linux 風(fēng)格的選項(xiàng)更加通用瓢省,因此這里將使用 linux 風(fēng)格的選項(xiàng)弄息。有些選項(xiàng)可能需要指定值,選項(xiàng)的賦值方式一般有兩種形式:
    • 選項(xiàng) 值勤婚,如 mysql --host localhost.
    • 選項(xiàng)=值摹量,如 mysql --host=localhost.
  • 位置參數(shù)(positional argument)往往是命令中的必選參數(shù)。如 git 中的切換分支命令馒胆,你必須要指定一個(gè)分支荆永,因此這里分支名就是一個(gè)必選參數(shù)。又比如打開文件命令国章,文件是必選項(xiàng),因此文件應(yīng)該是打開文件命令的一個(gè)位置參數(shù)豆村。但是位置參數(shù)也不一定是必選的液兽,在一些命令中,也有可能包含一些可選的位置參數(shù)掌动。一般情況下四啰,位置參數(shù)會(huì)放在命令的最后。由于位置參數(shù)的使用相對(duì)來說沒有那么嚴(yán)格粗恢,因此在一些的命令中柑晒,都沒有位置參數(shù)。比如 ls 命令眷射。位置參數(shù)必須要在前面加上任何前導(dǎo)符匙赞,如 curl [options...] <url> 命令中,最后的 url 就是位置參數(shù)妖碉。

2 示例說明

介紹完參數(shù)的基本組成之后涌庭,接下來我們就開始設(shè)計(jì) bat 的參數(shù)解析方式了。由于我們使用 bat 腳本往往不會(huì)實(shí)現(xiàn)太復(fù)雜的功能欧宜。因此這里設(shè)計(jì)的參數(shù)解析也有一些簡(jiǎn)化坐榆,這里并不會(huì)使用位置參數(shù),需要位置參數(shù)的地方冗茸,我們可以使用必須選項(xiàng)來代替席镀。這里的參數(shù)解析主要實(shí)現(xiàn)以下功能:

  • 選項(xiàng)包括長(zhǎng)選項(xiàng)和短選項(xiàng)兩種方式。
  • 選項(xiàng)包括需要賦值的選項(xiàng)和無需賦值的選項(xiàng)夏漱。
  • 選項(xiàng)參數(shù)無效的時(shí)候給出錯(cuò)誤警告豪诲。

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

這個(gè)示例代碼是用來實(shí)現(xiàn) c++ 庫的自動(dòng)編譯、測(cè)試麻蹋、打包跛溉、測(cè)試包的流程。由于這里我們主要是學(xué)習(xí)如何使用 bat 的參數(shù)解析。因此具體的執(zhí)行內(nèi)容其實(shí)我們不用關(guān)心芳室。這里一共使用了三個(gè)參數(shù):

  • -v, --vir_env 用來指定 python 的虛擬環(huán)境名稱专肪。這是一個(gè)帶值的選項(xiàng)。這里注意獲取到值時(shí)堪侯,需要額外執(zhí)行一次 shift嚎尤。
  • -f, --force 如果之前已經(jīng)打包過相同的包了,是否覆蓋之前的包伍宦。這是一個(gè)不帶值的選項(xiàng)芽死。
  • -h, --help 用來顯示幫助信息。

在輸入其他無效的選項(xiàng)時(shí)次洼,會(huì)報(bào)錯(cuò)关贵。這里在實(shí)現(xiàn)的時(shí)候需要注意一下幾點(diǎn):

  • 由于 bat 腳本的 if 語句中,無法實(shí)現(xiàn)兩個(gè)條件的“或”運(yùn)算卖毁,所以這里使用兩個(gè) if 語句來分別判斷一個(gè)選項(xiàng)的長(zhǎng)短形式揖曾,同時(shí)還使用了一個(gè)中間變量保存設(shè)置結(jié)果。
  • 部分變量的引用使用 !變量! 的形式亥啦,而不是 %變量% 的形式炭剪。這是為了保證這些變量能夠延后解析。如果使用 %變量% 來引用變量翔脱,這些變量并不會(huì)隨著我們的賦值而改變奴拦。同時(shí)需要注意的是 !變量! 的引用形式需要聲明 setlocal EnableDelayedExpansion
  • bat 腳本在執(zhí)行命令的時(shí)候并不會(huì)因?yàn)槊顖?zhí)行出錯(cuò)而停止届吁。因此我們需要通過判斷 errorlevel 這個(gè)變量來判斷之前的一個(gè)命令是否執(zhí)行成功错妖,如果執(zhí)行失敗可以選擇退出腳本。

其他的語句要么比較容易理解疚沐,或者是和業(yè)務(wù)相關(guān)無需關(guān)心站玄,因此這里不再介紹了。

參考資料:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末濒旦,一起剝皮案震驚了整個(gè)濱河市株旷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌尔邓,老刑警劉巖晾剖,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異梯嗽,居然都是意外死亡齿尽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門灯节,熙熙樓的掌柜王于貴愁眉苦臉地迎上來循头,“玉大人绵估,你說我怎么就攤上這事】睿” “怎么了国裳?”我有些...
    開封第一講書人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)全跨。 經(jīng)常有香客問我缝左,道長(zhǎng),這世上最難降的妖魔是什么浓若? 我笑而不...
    開封第一講書人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任渺杉,我火速辦了婚禮,結(jié)果婚禮上挪钓,老公的妹妹穿的比我還像新娘是越。我一直安慰自己,他們只是感情好碌上,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開白布英妓。 她就那樣靜靜地躺著,像睡著了一般绍赛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辑畦,一...
    開封第一講書人閱讀 50,043評(píng)論 1 291
  • 那天吗蚌,我揣著相機(jī)與錄音,去河邊找鬼纯出。 笑死蚯妇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的暂筝。 我是一名探鬼主播箩言,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼焕襟!你這毒婦竟也來了陨收?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤鸵赖,失蹤者是張志新(化名)和其女友劉穎务漩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體它褪,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饵骨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茫打。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片居触。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妖混,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出轮洋,到底是詐尸還是另有隱情制市,我是刑警寧澤,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布砖瞧,位于F島的核電站息堂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏块促。R本人自食惡果不足惜荣堰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望竭翠。 院中可真熱鬧振坚,春花似錦、人聲如沸斋扰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽传货。三九已至屎鳍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間问裕,已是汗流浹背逮壁。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粮宛,地道東北人窥淆。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像巍杈,于是被迫代替她去往敵國(guó)和親忧饭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351