第二章:Improving On User Commands--21.在手册页的数据库中搜索

   Unix的man命令有一个非常有用的选项,它产生一个手册页的列表,该列表的描述会包括特定单词。通常这个功能用man -k来实现,但它同样也可以通过apropos或是whatis命令实现。
   使用man命令来搜索一个词是很有用的,但这只完成了一半,因为一旦你得到了一系列的匹配,你可能仍然会觉得你自己要执行一个强力搜索,一次一个手册页的来查找你所需要的特定命令,
   作为一个小巧的备选项,这个脚本生成了一个可能的手册页列表,它匹配一个特定的模式,然后接着就搜索每一个匹配到的手册页来查找第二个模式。为了给输出一点约束,它也允许用户指定要搜索哪个手册页。
   小贴士: man手册页是分数字组成的:1 = 用户命令, 3 = 库函数, 8 = 系统工具等等。你可以通过man intro来搞清楚你的系统组成体系。

代码:

#!/bin/sh

# findman.sh -- 指定一个模式以及手册页号码
# 从有关的手册页中显示所有匹配该模式的内容

match1="/tmp/$0.1.$$"
matches="/tmp/$0.$$"
manpagelist=""

trap "rm -f $match1 $matches" EXIT  # 捕获到脚本正常退出的话,就删除这2个临时文件

case $# in
    3) section="$1" cmdpat="$2" manpagepat="$3";;
    2) section=""   cmdpat="$1" manpagepat="$2";;
    *) echo "Usage: `basename $0` [section] cmdpattern manpagepattern" >&2
       exit 1
esac

if ! man -k "$cmdpat" | grep "($section" > $match1; then
    echo "No matches to pattern \"$cmdpat\". Try something broader?" >&2
    exit 1
fi

cut -d\( -f1 < $match1 > $matches
cat /dev/null > $match1             # 清空文件

for manpage in $(cat $matches)
do
    manpagelist="$manpagelist $manpage"
    man $manpage | col -b | grep -i $manpagepat | \
      sed "s/^/${manpage}:/" | tee -a $match1    # sed的目的是在行首添加要查找的命令名
done                           # tee命令在写入文件的同时写到标准输出,-a是追加写模式

if [ ! -s $match1 ]; then
    cat << EOF
Command pattern "$cmdpat" had matches, but within those there were no
matches to your man page pattern "$manpagepat".
Man page checked: $manpagelist
EOF
fi

exit 0

 

脚本如何运行:
这个脚本并没有它第一眼看上去的那样简单。它利用了这样一个事实:命令的返回码取决于命令的执行情况。下面这行代码就是利用这点来判断是否有匹配变量cmdpat的值。grep命令的返回码就是重点:

if ! man -k "$cmdpat" | grep "($section" > $match1; then

如果grep没有查到符合条件的结果,它就会返回一个非0值(要知道,if判断成功的条件是它的条件是0值)。所以,我们压根不需要看$match1是不是一个大小大于0的文件。这种方法,可以较快速的达到我们的要求。

$match1文件中的每一行,都具有如下的格式:

httpd    (8) - Apache hypertext transfer protocol server 

cut -d\( -f1 的意思是以左括号为分隔符,然后只取得第一个域。一旦生成了匹配命令文件,下面就可以在每个命令的手册页中搜索manpagepat了。为了搜索手册页,内部的演示格式必须要格式化好,在这儿使用了 col -b。(注,col是过滤控制字符命令,-b参数是过滤掉所有的控制字符)

为了确保能够生成有效的错误信息,即可以查到该命令,但是查不到manpagepat时,会报一个错误信息,使用下面的一行代码,它把输出追加到一个临时文件中,同时打到标准输出:

sed "s/^/${manpage}:/" | tee -a $match1

然后if的! -s测试表示如果$match1这个输出文件的大小为0,那就显示错误信息。

运行脚本:
注意该脚本运行时需要的参数,最多3个,最少2个。

运行结果:
注,书上用的是测试httpd.conf,老七的机器上并没有这个模块。所以简单测试下awk好了。

先用原先的man -k pgawk
gawk [pgawk]         (1)  - pattern scanning and processing language

再用该脚本测试下3个参数齐全的情况:

./findman.sh 1 awk pgawk 
gawk:       pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk:       pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...
gawk:       Pgawk is the profiling version of gawk.     It is identical in every  way
gawk:         sion of the program.  When run with pgawk, the profile contains
gawk:       pgawk accepts two signals.  SIGUSR1 causes it to dump  a     profile  and
gawk:       pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk:       pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...
gawk:       Pgawk is the profiling version of gawk.     It is identical in every  way
gawk:         sion of the program.  When run with pgawk, the profile contains
gawk:       pgawk accepts two signals.  SIGUSR1 causes it to dump  a     profile  and

再测试下2个参数的情况:

./findman.sh awk pgawk  
gawk:       pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk:       pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...
gawk:       Pgawk is the profiling version of gawk.     It is identical in every  way
gawk:         sion of the program.  When run with pgawk, the profile contains
gawk:       pgawk accepts two signals.  SIGUSR1 causes it to dump  a     profile  and
gawk:       pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk:       pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...
gawk:       Pgawk is the profiling version of gawk.     It is identical in every  way
gawk:         sion of the program.  When run with pgawk, the profile contains
gawk:       pgawk accepts two signals.  SIGUSR1 causes it to dump  a     profile  and

最后,再测试下打印错误信息的情况:

./findman.sh 1 awk why
Command pattern "awk" had matches, but within those there were no
matches to your man page pattern "why".
Man page checked:  a2p gawk gawk [pgawk] igawk states

   最后总结下这个脚本。这个脚本的目的是深入到手册页的数据库中,然后按照自己的要求定制查询内容,显示查询结果或者错误信息。最后那个参数就是你要看的命令中要有的内容。这个脚本同样显示出了shell的强大之处,在unix的世界中,想怎么玩都行呀。

posted @ 2012-12-25 10:10  十舍七匹狼  阅读(157)  评论(0编辑  收藏  举报