查询程序是否存在PATH中
时间:2008-03-21 来源:剑心通明
使用环境变量的shell脚本(如MAILER和PAGER)存在一些隐藏的危险,可能有部份设置是指向不存在的程序。举个例子说下,在显示脚本的 输出时,如果我们选择灵活性强的PAGER设置来取代一个制式的特定工具,那么要如何确保PAGER值是指向一个存在的程序呢?而如果它是指向一个不存在 的程序,那么脚本将会中断。下面这个脚本会帮我们判断程序是否存在于PATH中,同时它也可以作为一个在不同工作环境中使用脚本技术(包含方程式与变数) 的良好范例。
脚本源代码
#!/bin/sh
# inpath - 证实我们所提供的程序是否能够执行
# 或存在于系统的设定的PATH中
in_path()
{
# 给出一个路径及命令,脚本尝试去查询这个命令
# 如果在PATH中找到并且可以执行,则返回0,否则返回1
# 它将暂时修改IFS的值,执行后即恢复IFS的值.
cmd=$1 path=$2 retval=1
oldIFS=$IFS IFS=":"
for directory in $path
do
if [ -x $directory/$cmd ] ; then
retval=0 # 在指定的目录($directory)中找到指令($cmd),返回0
fi
done
IFS=$oldIFS
return $retval
}
checkForCmdInPath()
{
var=$1
# 下面的变量运作需要作下说明:${var#expr}会留下变量中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
}
*************************************************************
注意:我编写的脚本要存放到哪里去?
我 建议你在主目录(home目录)下新增一个名为"scripts"的新目录,并将其完整的路径加在PATH的变量中。我们可以通过echo $PATH指令来查看正确的PATH。要修改来修改PATH变量的话,使用vi工具去编辑你的主目录下的".login"或".profile"文档,, 以符合我们的需求。
**************************************************************
运行脚本
在执行这个脚本程序之前,我们必须在这段代码后再附加上一段,让它能够对前面执行的传回值进行判断,代码如下:
if [ $# -ne 1 ] ; then
echo "Usage: $0 command" >&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
把上面的代码添加到原先的脚本代码后,我们就完成该脚本,可以运行并显示结果啦。如果你觉得这段新加上去的代码会很难理解,可以考虑将它去掉或者将其注释掉。
结果
我们分別准备三个档案来测试inpath程序:第一个是存在的档案、第二个也是存在的档案,但它的路径并不在PATH的设定中,第三个档案我们会输入完整的路径与档案名,但它并不存在。
$ inpath echo
echo found in PATH
$ inpath MrEcho
MrEcho not found in PATH
$ inpath /usr/bin/MrEcho
/usr/bin/MrEcho not found or not executable
改进与加强
或 许这个程序较特別的部份是利用POSIX的变量分配方式:${var%${var#?}}。我们来探讨这个表达式,其实它是个表面复杂,但实际上却是两个 巢状的字串。在巢状字串里层的是${var#?},用来分离var变量第一个字元后的字串(? 是一个万用字元,代表着任何一个字元)。接着外层的 ${vat%pattern} 将移除与pattern(即里层运算后的结果)相符的字串,再产生一个字串。从我们这个脚本来看,产生出来的字串将是第一个字元。
这是相 当复杂的解释。但关键就在 check- ForCmdInPath 的运作。由于变量可能是单独的档案名(echo)或是完整的路径与档案名(如 "/bin/echo"),check- ForCmdInPath必须分辨出两者之间的不同,它会去检查这个变数的第一个字元是否"/",因此我们必须先将变数的第一个字元分离出来。
如 果POSIX的变数让你觉得恐慌,bash与ksh支支持另一种变量方法:${varname:start:size},这个方式可以直接从变量 varname中的第"start"个字元取得"size"个字元。举例来说${varname : 0 : 1},将会从varname变量中的第1个字元开始,共取得1个字元。当然,如果还是不喜欢这种取字元的方法,也可以考虑另一种方法:$(echo $var | cut -c1)。