生成shell脚本调用树

时间:2011-02-24 19:51:13

标签: shell scripting graph-visualization

我已经交了一个包含几十个(可能超过100个,我没有计算过)bash脚本的项目。大多数脚本至少调用另一个脚本。我想得到一个调用图的等价物,其中节点是脚本而不是函数。

有没有现成的软件可以做到这一点?

如果没有,是否有人对如何做到这一点有聪明的想法?

我能想到的最佳计划是枚举脚本并检查基本名称是否唯一(它们跨越多个目录)。如果有重复的基本名称,则哭,因为脚本路径通常以变量名称保存,因此您可能无法消除歧义。如果它们是唯一的,那么grep脚本中的名称并使用这些结果来构建图形。使用一些工具(建议?)来可视化图形。

建议?

3 个答案:

答案 0 :(得分:3)

通过实现包装shell本身,记录调用包装器的人并执行原始shell。

是的,你必须启动脚本才能识别真正使用的脚本。否则你需要一个与shell引擎本身具有相同知识的工具来支持整个变量扩展,PATH等 - 我从来没有听说过这样的工具。

为了使调用图形可视化,请使用GraphViz的点格式。

答案 1 :(得分:2)

这里是我如何做到这一点(免责声明:很多都是黑客,所以如果你长期使用它,你可能想要清理)......

假设:   - 当前目录包含所有相关的脚本/二进制文件。   - 构建图形的文件在subdir call_graph中。

创建脚本call_graph / make_tgf.sh:

#!/bin/bash
# Run from dir with scripts and subdir call_graph
# Parameters:
# $1 = sources (default is call_graph/sources.txt)
# $2 = targets (default is call_graph/targets.txt)

SOURCES=$1
if [ "$SOURCES" == "" ]; then SOURCES=call_graph/sources.txt; fi
TARGETS=$2
if [ "$TARGETS" == "" ]; then TARGETS=call_graph/targets.txt; fi

if [ ! -d call_graph ]; then echo "Run from parent dir of call_graph" >&2; exit 1; fi
(
#  cat call_graph/targets.txt
  for file in `cat $SOURCES `
  do
    for target in `grep -v -E '^ *#' $file | grep -o -F -w -f $TARGETS | grep -v -w $file | sort | uniq`
    do echo $file $target
    done
  done
)

然后,我运行了以下内容(我完成了仅脚本版本):

cat /dev/null | tee call_graph/sources.txt > call_graph/targets.txt
for file in *
do
  if [ -d "$file" ]; then continue; fi
  echo $file >> call_graph/targets.txt
  if file $file | grep text >/dev/null; then echo $file >> call_graph/sources.txt; fi
done

# For scripts only:
bash call_graph/make_tgf.sh call_graph/sources.txt call_graph/sources.txt > call_graph/scripts.tgf

# For scripts + binaries (binaries will be leaf nodes):
bash call_graph/make_tgf.sh > call_graph/scripts_and_bin.tgf

然后我在yEd中打开了生成的tgf文件,并让yEd进行布局(Layout - > Hierarchical)。我保存为graphml,将手动编辑的文件与自动生成的文件分开。

我发现某些节点在图表中没有帮助,例如在整个地方调用的实用程序脚本/二进制文件。因此,我从sources / targets文件中删除了这些文件,并根据需要重新生成,直到我喜欢节点集。

希望这有助于某人...

答案 2 :(得分:0)

在每个shell脚本的开头插入一行,#! line,记录时间戳,脚本的完整路径名和参数列表。

随着时间的推移,你可以挖掘这个日志以识别可能的候选者,即非常靠近的两行记录第一个脚本调用第二个脚本的可能性很高。

这也使您可以专注于仍在使用的脚本。

您可以使用ed脚本

1a
log blah blah blah
.
wq

然后像这样运行:

find / -perm +x -exec ed {} <edscript

确保使用-print而不是exec子句测试find命令。和/可能不是您想要使用的路径。如果你必须包含bin目录,那么你可能需要切换到grep以识别要包含的路径名,然后当你有一个完整的正确名称的文件时,使用xargs而不是find来运行脚本。