第一章:The Missing Code Library--1.在系统路径PATH中寻找程序
每个章节中的脚本独立成文。
代码已测试过,Bash版本:GNU bash, version 3.00.15(1)-release (i686-asianux-linux-gnu)
使用环境变量的Shell脚本,有一个隐藏的危险:它们可能部分正确的指向不存在的程序。比如你决定使用环境变量PAGER来灵活的演示脚本输出,而不是通过编写一个特殊的工具,那么如何确定PAGER这个值已经设置正确了呢?毕竟它不是一个有效的程序,你的脚本可能会崩溃。
下面的这个脚本表明了在系统路径中,如何通过测试来确定一个给定的程序能否查找得到。同时,它也很好的演示了一系列不同的脚本技术,包括脚本函数和变量切片(slicing)。
第一个脚本
inpath.sh ---- 在系统路径PATH中寻找程序
inpath.sh
#!/bin/sh in_path() { # 给定一个命令和路径,尝试找到命令。 # 如果找到了,并且可执行,返回0,否则返回1. # 注意,它暂时性的修改了IFS(输入域分隔符),但完成后会重置。 cmd=$1 path=$2 retval=1 oldIFS=$IFS IFS=":" # 设置域分隔符 for directory in $path do if [ -x $directory/$cmd ]; then retval=0 # 执行到这步,表明在PATH中找到了程序 fi done IFS=$oldIFS # 还原域分隔符 return $retval } checkForCmdInPath() { var=$1 # 提示用法: # ${var#expr},从var开头删除最短匹配expr的字符串 # ${var%expr},从var结尾位置删除最短匹配expr的字符串 # 在Bash中,使用${var:0:1}和cut -c1也可以。 if [ "$var" != "" ]; then if [ "${var%${var#?}}" = "/" ]; then if [ ! -x $var ]; then return 1 fi elif ! in_path $var $PATH; then return 2 fi fi }
测试inpath.sh:向验证程序传递一个初始参数,然后验证返回码。下面的代码直接添加在inpath.sh中。
inpath.sh
1 if [ $# -ne 1 ]; then 2 echo "Usage: $0 commmand" >&2 3 exit 1 4 fi 5 6 checkForCmdInPath "$1" 7 case $? in # $?是上个命令或是脚本的退出码 8 0)echo "$1 found in PATH";; 9 1)echo "$1 not found or not executable";; 10 2)echo "$1 not found in PATH";; 11 esac 12 13 exit 0
测试的3种情况:
1.程序存在:
inpath.sh python
输出:python found in PATH
2.程序存在,但不在PATH上:
inpath.sh test.sh
输出:test.sh not found in PATH
3.程序不存在,但该程序有一个完整的包含路径的名字:
inpath.sh /usr/bin/python4
输出:/usr/bin/python4 not found or not executable
其中,python大家都知道的,test.sh是一个可执行文件,python4估计这几年都不会有的,哈哈。
分析下上面的脚本
上面代码中最不常用的地方可能就是:
${var%${var#?}}
它是POSIX的变量切片方法。它有2个嵌套,内部嵌套 ${var#?},取得除变量var第一个字母外的剩余内容,其中?是一个正则表达式,表示通配一个字符。外层 ${var%pattern},生成一个除去右匹配pattern后的剩余子串。在此例中,剩下的就是字符串的第一个字母。
check-ForCmdInPath可以区分是一个程序还是一个包含有路径的文件名。方法是判断第一个字母是不是斜线“/”。
如果上面的切片方法使用起来有难度的话,可以使用另一种Bash和Ksh支持的方法,子串函数
${varname:start:size}
比如,${varname:1:1}就是产生一个只有第一个字母的子串。注意,Shell中的这种用法,字符串下标是从1开始的。当然了,如果这2种技术你都不爱用的话,但是又想只取第一个字母,可以用cut命令:
$(echo $var | cut -c1)


浙公网安备 33010602011771号