【问题标题】:Generate shell script call tree生成 shell 脚本调用树
【发布时间】:2011-02-24 19:51:12
【问题描述】:

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

是否有任何现有的软件可以做到这一点?

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

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

建议?

【问题讨论】:

  • Graphviz 是一个很好的可视化工具,但在将其传递给 graphviz 之前,您需要以某种方式预处理您的 basename 输出。您可以尝试使用 bashdb 来调试您的脚本。
  • 这些天我经常做的是在我创建的每个脚本的开头添加一个 Depends: 注释。在更大范围内作为事后的想法可能不可行,但这是一个非常简单的约定,对我很有帮助。

标签: shell scripting graph-visualization


【解决方案1】:

通过您的实现包装外壳本身,记录谁调用了您包装器并执行原始外壳。

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

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

【讨论】:

  • 为聪明点赞。也许我没有创造力,但我从来没有想过包裹外壳。不幸的是,运行所有这些对我来说是不切实际的。我什至不知道他们中的大多数人做什么或哪些是重要的。我同意变量扩展和路径问题很难,但我必须根据代码来做,或者没有它就活下去。
  • 好的,如果您正在考虑新的实现,请考虑采用原始 shell 源代码(开源?)并在那里添加您的逻辑。您将以更少的价格获得解析器。尝试禁用除 shell 脚本本身之外的所有 exec() 调用并记录您要查找的内容。因为我从来没有听说过这样的项目,所以我会很高兴从你这里了解你的进展。祝你好运。
【解决方案2】:

这就是我最终这样做的方式(免责声明:其中很多都是 hack-ish,所以如果你打算长期使用它,你可能需要清理一下)...

假设: - 当前目录包含所有有问题的脚本/二进制文件。 - 用于构建图的文件放在 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 进行布局(布局 -> 分层)。我保存为 graphml 以将手动可编辑的文件与自动生成的文件分开。

我发现有些节点在图中没有帮助,例如到处调用的实用程序脚本/二进制文件。所以,我从源/目标文件中删除了这些,并根据需要重新生成,直到我喜欢节点集。

希望这对某人有所帮助...

【讨论】:

  • 我无法设置 yEd。是否有其他方法可以查看 TGF 文件?
【解决方案3】:

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

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

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

你可以使用 ed 脚本

1a
log blah blah blah
.
wq

然后像这样运行它:

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

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

【讨论】:

  • 哦,你还需要写一个日志脚本或者最好是一个shell别名/函数。
猜你喜欢
  • 2015-01-23
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-22
  • 2014-06-05
  • 2018-03-25
  • 2012-01-11
相关资源
最近更新 更多