Shell脚本解析命令行参数——Argparse(填坑)

一、概述

  在编写shell脚本时经常会遇到一个问题,即传递命令行参数。如果只考虑最简单的应用场景,即所有参数都按顺序,显示传递进去,shell脚本倒是非常方便,终端直接传,脚本里面对应顺序的参数用 $1,$2.. 等表示即可。这种用法对应Python中的sys.argv参数传递模式。不过当参数数量较多时,我们往往希望某些参数能提供默认值,从而只需传递少量参数即可运行。熟悉Python的朋友应该都使用过Argparse模块。该模块提供了常用的命令行参数解析功能,包括设置参数类型,默认值,选择范围等,当然还有便捷的输入提示(不要小看了这个功能,没有合理的参数提示,会对他人的使用造成很大不便,而且过一段时间自己也不记得运行时的细节...)。

1.1 问题分析

  总结一下,个人认为命令行解析可分成三个不同level的问题:

  • I. 简单参数传递,无解析。这种模式可以在写脚本一时获取廉价的快感,毕竟用python写个argparse也得好几行,如果用sys.argv或者shell传递几乎没有工作量。

  • II. 参数设置默认值。该问题稍复杂但是有时候是必须面对的。当然对于这个问题,如果还想偷懒也不是不可以。比如在一些简单脚本中我就经常用下面的写法来😁 (注意python脚本的脚本名占 了第一个参数~)

if [[ $# < 2 ]]   # Shell
then 
    var=default_value
else 
    var=$2   
fi

if len(sys.argv) < 3:   # Python
    var = default_value
else:
    var = sys.argv[2]   

  然而这种根据参数数目来过滤的写法,很难在多个参数时针对性的设置默认值。这个级别的参数传递问题由于也比较常用,Python的话用argparse设置default即可,但是shell脚本就比较麻烦,具体的解决办法见下文。

  • III. 完善的参数解析
      如果前两个级别的参数解析,在自己编写脚本时还能凑合使用,那么最后一级别的参数解析应该可以视为一个开发者必备的工具了。完善的脚本在团队开发和代码维护中可以减少很多不必要的交接过程和重复工作。一个常见的场景是SDK的封装,一方面开发者希望保留足够的参数接口用于调试,另一方面又不希望要求用户提供大量输入参数。对于Python脚本,argparse完全够用,即使是pyinstaller类似的封装工具,也可以无脑支持使用argparse解析的脚本。然而linux环境下,我暂时还没找到这一级别对应的解析方法...😹,如果哪位朋友有经验,请不吝赐教~

二、Shell命令行设置默认参数

  其实我目前只有一个比较生硬的办法,而且并不是用主流的getopts或者getopts,一方面目前还没有编写大型shell脚本的需求(稍微复杂的功能还是Python实现优先),另一方面,看到getopts的example就放弃了...参数解析部分的代码比我脚本都长...

  废话终于说完了。现在上代码,除了有一些限制,可以说是无脑使用了。看一个例子:test_args.sh

#!/bin/sh
until [ $# -eq 0 ]
do
  name=${1:1}; shift;
  if [[ -z "$1" || $1 == -* ]] ; then eval "export $name=true"; else eval "export $name=$1"; shift; fi  
done
echo "year=$year month=$month day=$day flag=$flag"

运行方式:
sh test_args.sh -year 2017 -flag -month 12 -day 22
输出:
year=2017 month=12 day=22 flag=true

经过几次实验,我总结出这种参数解析的用法:

  • 传递的形参名和实参名一致,且形参前加 "-",后面紧跟对应实参
  • 参数顺序随意
  • bool型参数无需显式传递值(上面的-flag

  那我们关系的默认参数设置问题解决了吗?答案是,至此还没有。观察下实验的输出:

观察测试脚本输出结果

可以看出几个现象:

  • 用这种解析方式,$#命令不能给出正确的有效参数个数,因为它会按照正常shell脚本的参数(以空格隔开)来判断输入个数。
  • 未传入的参数,显示值为空(等号后面没东西)。

  根据这一观察,我们其实有一个比较粗暴的设置默认值的方法,即先判断某个指定参数是否为空,如果为空就给他赋一个值...否则就用实参的值。不过这里又出现一个问题,等号后面的空白代表啥?
  首先排除Python里的None😒...其实我最后也没发现那个空白是啥符号...不过我发现一个判断条件,就是判断该参数的长度是否为0。
  完整的Argparser模板可以是这样:

##########  argparser  ###########
until [ $# -eq 0 ]
do
  name=${1:1}; shift;
  if [[ -z "$1" || $1 == -* ]] ; then eval "export $name=true"; else eval "export $name=$1"; shift; fi
done
########## set default  ###########
if [ ${#my_arg} == 0 ]
then
    my_arg=XXXX;  # default value to give    
else
    my_arg=$my_arg;
fi

  所以这就是我目前对shell命令行参数设置默认值的处理方法...显然,这不是最优的方法,但是对于逻辑简单的shell脚本也够用了(相比完全不解析参数还是有质的飞跃😁)

  后续如果有稍微复杂一些的需求,可能会继续更新~如果有朋友有更好的方法,还请多多交流!

三、 更新: 使用getopts:

 declare others=${@:4}
 function Argparser () {
     while getopts 'c:lh' arg "$@";
     do     
         case $arg in
           'c')
              custom_config="--custom $OPTARG"
              ;;  
           'o')
              is_online="--online"
              ;;  
           'l')
              use_local_config="--local_config"
              ;;  
           'h')
              echo "TBD"
              exit
              ;;  
           ?) 
              echo "UNKNWON ARGS: ${OPTARG} "
              exit 1
              ;;  
         esac
     done  
 }            
 Argparser ${others}

参考:

[1] https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,362评论 0 5
  • 转自:http://blog.xiayf.cn/2013/03/30/argparse/ argparse是pyt...
    MADAO123阅读 1,749评论 0 0
  • .bat脚本基本命令语法 目录 批处理的常见命令(未列举的命令还比较多,请查阅帮助信息) 1、REM 和 :: 2...
    庆庆庆庆庆阅读 8,036评论 1 19
  • 你是众多生灵中的一个 不要期待获得得比她多 没有人说话 那就自己唱一首歌 唱蓝天白云草地牛羊 或者是妈妈 不要企图...
    小小仲马阅读 254评论 0 1
  • 1.《明星大侦探》1―3季 嘉宾阵容强大:双北(何炅撒贝宁)推理王,鬼鬼(吴映洁)搜证犬,小白(白敬亭)密室王,王...
    落欢颜阅读 656评论 1 2