shell 补齐路径_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. 先处理默认主机 IP4 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 ip10 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+117 else

args_list="${args_list#*${delim}}"  ## 需要处理的参数列表

46 fi

47 dmsg "the_end=$the_end" && echo

48 done ## 处理循环结束

49 }

最后

运行:tftp_multi_da "$@"

收工:exit 0

参考文献

《Unix 编程艺术》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值