第一章: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
 if [ $# -ne 1 ]; then
     echo "Usage: $0 commmand" >&2
     exit 1
 fi
 
 checkForCmdInPath "$1"
 case $? in                         # $?是上个命令或是脚本的退出码
     0)echo "$1 found in PATH";;
     1)echo "$1 not found or not executable";;
     2)echo "$1 not found in PATH";;
 esac
 
 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)

你可能感兴趣的:(linux,shell,bash)