sample.txt表示一张图的关系:A -> {B;C}表示为从A结点到B和C结点都有一条路径,B或C如果没有出现在"->"的左边,表示B或C为终结点,图中没有环。这也可以表示为一个程序中的函数调用关系,图中没有环说明函数调用过程中没有对某函数的直接递归或间接递归调用。写一个shell脚本程序,找出以某函数为起始结点的调用图。
sample.txt
1 -> {0};
2 -> {0};3 -> {2;1};
5 -> {4;3;2};
7 -> {3;2;6};
8 -> {7;6;5;4;3};
9 -> {8;7;6};
------------------------------------
程序思想:
1.将“->"左侧的标号保存在globalseqnums变量中
2.先根据输入的结点号找到其在sample.txt 的对应行,并保存在变量line中;
3.将line中箭头右侧部分截取出来,保存在变量arrowright中;
4.将‘{’和‘}’去掉,并将各标号用空格隔开,以单词形式识别
5.对4中每一个单词标号进行查找,如果在globalseqnums中有匹配,则说明其是中间节点;如果没有匹配,则说明是终结点
6.在5中如果是中间结点,则先将标号保存在savedseqnum变量中,然后递归调用,重复2到4过程;如果是终结点,返回到上一层递归调用
get_call_graph.sh
#!/bin/bash
filename=
globalseqnums=
savedseqnum=
space=" "
function find_spec_line()
{
if [ $# -ne 1 ]
then
echo "usage: find_spec_line <num>"
exit 1
fi
local submark=$1
local string=`sed -n '/^'$submark' /p' $filename`
echo $string
}
function get_arrowright()
{
if [ $# -ne 1 ]
then
echo "usage: get_arrowright <string>"
exit 1
fi
local string=$1
local arrowright=`echo $string|awk -F " -> " '{print $2}'`
echo $arrowright
}
function strip_arrowright()
{
if [ $# -ne 1 ]
then
echo "usage: strip_arrowright <string>"
exit 1
fi
local str=$1
local striped=`echo $str|sed 's/{//g'|sed 's/};//g'`
striped=`echo $striped|awk -F ";" '{for(i=1;i<=NF;i++)print $i}'`
echo $striped
}
function search()
{
local word
local line
local arrowright
local striped_arrowright
if [ $# -ne 1 ]
then
echo "usage: search <string>"
exit 1
fi
word=$1
echo $savedseqnum|grep -w $word 2>&1 > /dev/null
if [ $? -ne 0 ]
then
savedseqnum=$savedseqnum$word$space
fi
line=`find_spec_line "$word"`
arrowright=`get_arrowright "$line"`
striped_arrowright=`strip_arrowright "$arrowright"`
for word in $striped_arrowright
do
echo $globalseqnums|grep -w $word 2>&1 > /dev/null
if [ $? -eq 0 ]
then
echo $savedseqnum|grep -w $word 2>&1 > /dev/null
if [ $? -ne 0 ]
then
savedseqnum=$savedseqnum$word$space
fi
search "$word"
else
return
fi
done
}
function display_call()
{
local line
local start=0
if [ $# -ne 1 ]
then
echo "usage: display_call <string>"
exit 1
fi
seqnums=$1
for num in $seqnums
do
line=`sed -n '/^'$num' ->/p' $filename`
if [ -n "$line" ]
then
if [ $start -eq 0 ]
then
start=1
echo $line > newsample.txt
else
echo $line >> newsample.txt
fi
fi
done
}
filename=sam1
globalseqnums=`awk -F " -> " '{print $1}' $filename`
num_to_print=$1
search "$num_to_print"
echo $savedseqnum
display_call "$savedseqnum"
cat newsample.txt
----------------------------------------------------------------------------------
root# get_call_graph.sh 9
9 8 7 3 2 1
9 -> {8;7;6};
8 -> {7;6;5;4;3};
7 -> {3;2;6};
3 -> {2;1};
2 -> {0};
1 -> {0};
root# get_call_graph.sh 5
5 4 2 3 1
5 -> {4;3;2};
4 -> {2;0};
2 -> {0};
3 -> {2;1};
1 -> {0};
程序能够实现要求,就是效率有些低,刚开始学习shell编程,还没有想到其他好算法。