我有大量的脚本需要修改。每个脚本可能会调用 5 到 10 个其他脚本,这些脚本又可能会调用其他几个脚本,谁知道这个兔子洞有多深。
有没有办法获取特定脚本调用的脚本列表?
我在想这样的事情:
/home/root/ $ showscripts mytargetscript
Run Code Online (Sandbox Code Playgroud)
输出将类似于:
/home/root/mytargetscript
/home/root/asubscript
/home/root/bsubscript
...
Run Code Online (Sandbox Code Playgroud)
如果我冒犯了 Unix 诸神,我会提前忏悔。我在 dba.se 上回答了很多问题。
没有通用的解决方案,因为脚本可以使用无数种方式来调用其他脚本。你可以做一个grep
可能适用于你的脚本但不是一般的。
这调用了哪些脚本?
$(find / -executable -name "*.sh" -print0 | shuf -z -n 1)
Run Code Online (Sandbox Code Playgroud)
如果您能够实际运行这些脚本,则可以通过两种方式跟踪它们。
set -x
Run Code Online (Sandbox Code Playgroud)
将使您的脚本以扩展形式打印它执行的每个命令。然后,您可以检查那些运行脚本的命令。
strace -ff
Run Code Online (Sandbox Code Playgroud)
矫枉过正,但strace
为您提供了一个过程所做的一切,并且有了这个-ff
选项,它也几乎跟随兔子洞到它的尽头。我说几乎是因为有办法绕过它。它是否遵循守护进程?
Grep strace
for 调用open()
orexec*()
并过滤它的脚本文件,您可能接近完整图片[对于您所做的脚本的一次运行 - 不计算仅在其他条件下调用的脚本]。
$ strace -ff ./testscript.sh |& grep 'open.*\.sh"'
open("./testscript.sh", O_RDONLY) = 3
[pid 24486] open("./CD-DVD Image erstellen.sh", O_RDONLY) = 3
Run Code Online (Sandbox Code Playgroud)
因此,您可以对您的解决方案进行创新,只是不要指望一个适合所有情况的解决方案。
假设所有脚本都位于同一目录中,它们的名称中没有制表符或换行符,并且您在文件中拥有“有趣”脚本的列表scripts.txt
,每行一个,并且还假设您的 shell 可以进行<(...)
进程替换:
#! /bin/sh
while read -r s; do
fgrep -o -w -f <(fgrep -v -w "$s" scripts.txt) "$s" /dev/null | \
sort -u | \
tr : '\t' >>calls.txt
done <scripts.txt
Run Code Online (Sandbox Code Playgroud)
这会构建一个文件calls.txt
。该文件由制表符分隔的对组成script1 script2
,描述“script1
调用script2
”关系。
您需要输入calls.txt
以下 Perl 脚本:
#!/usr/bin/env perl
use v5.10;
use strict;
use warnings;
use Graph::Directed;
my $g = Graph::Directed->new;
while (<>) {
chomp;
$g->add_edge( split /\t/ );
}
for ( sort $g->vertices ) {
say "$_: " . join(', ', sort $g->all_successors($_));
}
Run Code Online (Sandbox Code Playgroud)
该脚本根据调用关系构建有向图,然后打印所有顶点的后继(即脚本)。
当然,该脚本需要Perl模块Graph
。假设您有该cpanm
脚本,您可以通过运行来安装所需的模块cpanm Graph
。