• shell 选项解析之需求一:多路径自动补全


    前言

    上篇实现了shell选项的简单解析,支持选项连写(-xfd)及带参选项(-d “目的路径”)。但在使用中发现仍有不便之处:经常需要上传多个文件到设备下的不同路径,若脚本只支持单路径,则只能按路径分批上传;其次,有些文件名比较长,输入麻烦,so,新的需求产生了~

    1)支持对文件指定不同目的路径

    2)考虑到不少情况下只是覆盖原文件,若目的路径可带文件名,则能利用shell的路径补全简化文件名的输入,即路径选项支持:-d /usr/bin/file_with_a_very_long_name

    【补630】唉,人都是有惰性的,若功能顺应了惰性,则惰性会打蛇随棍上,反向推动功能演化,这从侧面反映了科技与欲望的关系,所以西方科技曾被视为奇技淫巧是有文化根据的,呵呵。 言归正传,使用中发现,若支持文件名补全,则对于长点的文件名,都会有使用特性 2)的心理倾向,导致选项经常像这样 -d /usr/bin/file1, -d /usr/bin/file2, -d /opt/file3,不停的输入 -d 很麻烦,因为输入时需寻找“-”在键盘上的位置,从人体工学的角度来说,符号“-”的I/O时间远大于其它普通字符,导致输入流水线断流,违背了GTD中及时清空大脑的要求,叔婶均无可忍之。这样吧,若参数里带“/”,则认为是目的路径,前面带不带选项“-d”都行

    思考

    1、可以修改原脚本,在流程处理中添加对新需求的支持。但这样做会得不偿失,因为原脚本功能单一,遵循标准的选项处理方式。直接修改会破坏模块封装,引起功能紊乱,导致难以复用。若标准化封装模块是块平直的砖,则功能添加版就是块更大的砖,但不甚平直,前者可建高楼,后者就只能盖屋,太高就 Hold 不住撒~

    2、既然不改原模块,则考虑在原功能基础上实现。一个自然的想法是使新脚本支持批量选项,即 原选项1 分隔符 原选项2 分隔符 ...,这样的话,新脚本只需根据分隔符把各选项分割出来,然后传给标准模块处理即可,如, -xd /usr/bin snmp 分隔符 -d /opt/local webs ...,从而支持了多目的路径

    3、对文件名补全的支持:与 2 类似,也要转为选项的标准形式来处理,即把 -d /usr/bin/snmp 转为 -d /usr/bin snmp,把粘在一块的扯明白喽~

    4、其它考虑:多数情况下,都是从一台主机上传文件,所以约定,若最后一个参数为ip,则此ip作为所有选项的默认主机地址;

    目标

    支持多目的路径;支持带文件名路径

    例: -xfd /usr/bin/linux-2.6.13-mips-snmpv2 webs分隔符 -d /opt/local wtp 分隔符...  .68

    解释:把文件linux-2.6.13-mips-snmpv2,webs从主机192.168.0.68上传到设备的/usr/bin目录下,并后台执行;把文件wtp从192.168.0.68上传到/opt/local下...

    【补630】不要 -d 也支持,-xf /usr/bin/linux-2.6.13-mips-snmpv2 webs 分隔符 /opt/local wtp

    实现

    1. 分隔符的选择

    感觉标准点的,如 --add,但字符多了点; 分号“;”?不可,shell会试图解释,先用逗号顶上吧

    2. 如何分割选项

    直观的方法是依次把两个连续分隔符间的内容取出,标准化处理后作为参数传出。shell的字符串处理功能不弱,看看有哪些趁手的工具先~

    expr 命令,length求长度,index得索引,substr截取字符串,match根据正则表达式获得匹配串的长度和内容

          index + substr 方式,通过index 得到两个连续分隔符的位置,substr根据位置截取中间,但index只能匹配到第一个字符

          match,写个分隔符的正则,把之间的内容取出,但试了下,似乎是贪婪的方式哦,会取最大匹配

    忽然发现以上思路有偏差,依赖直观而没脚踏实地,从机器扫描的方式来看,从左至右,碰到一个分隔符,就该认为一个项已取完,可以送出了,然后删掉此分隔符,继续扫描。

    思路明确了,这里用子串削除来取得一项,${参数列表%%分隔符*},即右边取最大匹配,削掉丫的;至于格式的标准化,用for来选择处理

    3. 代码

     1 tftp_multi_da()
     2 {
     3    ## 1. 先处理默认主机 IP
     4    local args_list="$*"
     5    eval local last_arg=\"\${$#}\"  ## 获得最后一个参数
     6    dmsg "last_arg=$last_arg"
     7    local tail=""
     8    case $last_arg in .[0-9]* )  ## 是否 ip?
     9       tail=$last_arg  ## 保存默认 host ip
    10       args_list="${*%${last_arg}}";;  ## 保存后移除
    11    esac
    12    
    13    local delim=","  ## 分隔符
    14    local args=""  ## 项中的单个参数
    15    local the_end=0  ## 末项处理标识
    16    while local seg="${args_list%%${delim}*}"  ## 2. 分割出每项
    18 local seg_b="" ## 用来传出的标准化项 19 [ "$the_end" -eq 0 ] ## 若末尾项还未处理(实现类似 do-while) 20 do 21 if [ -n "$seg" ]; then 22 dmsg "seg=$seg" 23 for args in $seg ## 3. 分割出每项中的参数,准备标准化 24 do 25 dmsg "args=$args" 26 case $args in 27 -* ) prev_opt="$args" 28 dmsg "prev_opt=$prev_opt" 29 ;; 30 * ) case $prev_opt in
    -*d ) ## 根据上次保存的选项做处理 31 if [ ! -d "$args" ]; then 32 args="${args%/*} ${args##*/}" ## 分离路径和文件名 33 fi
    ;;
    * ) if [ $(expr index "$args" "/") -gt 0 ];then ## 630需求
    [ ! -d "${args}" ] && args="${args%/*} ${args##*/}"
    args="-d ${args}"
    fi
    ;;
    34 esac 35 dmsg "seg_b=$seg_b" 36 prev_opt="" 37 ;; 38 esac 39 seg_b="$seg_b $args" ## 4. 生成标准化项 40 done 41 42 [ -n "$seg_b" ] && parse_opt $tail $seg_b ## 5. 最终处理(代入默认ip) 43 fi 44 if [ $(expr index "$args_list" "$delim") -eq 0 ]; then ## 已到最后一项 45 let the_end=the_end+1
    17 else
    args_list="${args_list#*${delim}}"  ## 需要处理的参数列表 46 fi 47 dmsg "the_end=$the_end" && echo 48 done ## 处理循环结束 49 }

    最后

    运行:tftp_multi_da "$@"

    收工:exit 0

    参考文献

    《Unix 编程艺术》

  • 相关阅读:
    Android UI开发第十四篇——可以移动的悬浮框
    Android UI开发第八篇——ViewFlipper 左右滑动效果
    Android: Trusting SSL certificates
    Customize Android Fonts
    Android UI开发第三篇——popupwindow
    Android UI开发第四篇——实现像handcent sms或者chomp sms那样的气泡短信样式
    Android UI开发第一篇——android的九宫格式实现
    Android UI开发第十一篇——右上角带个泡泡
    Android开发之系统信息——获取Android手机中SD卡内存信息
    Android自动测试之MonkeyRunner之MonkeyImage
  • 原文地址:https://www.cnblogs.com/lookbackinside/p/2570749.html
Copyright © 2020-2023  润新知