2010-10-13 67 views
8

我正在寻找处理一个shell脚本来确定的一种方式:确定shell脚本的函数和文件依赖关系?

  1. 哪些命令,脚本或函数调用的脚本。
  2. 脚本(r或w)访问哪些文件。

它不需要通过依赖递减,只需列出它直接运行的内容即可。我可以自己写一些能够做到这一点的东西,但一定是在...之前完成的,我只是没有找到它。

+0

有趣的问题 - 非平凡回答。考虑跟踪'sh -x'的输出(但是它只显示你执行的命令,而不是那些没有执行的命令) – 2010-10-13 19:27:17

回答

1

这将是我目前开发的Loker项目的一项功能。目前,解析器已基本完成,您可以在其上实现一个合理的近似值。但是,一般来说,这项任务非常复杂,因为命令的名称可能来自可变扩展,字段分割等。

如果您描述了什么是您需要的,以及您要解析的是哪种脚本将能够说出Loker现在可以满足您的多少需求。

作为替代选项,某些版本的bash有--rpm-requires选项,它也有类似的功能。

+0

非常有趣,当我有时间的时候,我会更好地看看Loker,正确解析文件和可执行文件的代码确实是非常复杂的......我想通过使用UNIX来运行代码来跟踪文件访问可能是一种方法,我对这个事情一无所知......因此,这个幻想。 – mathtick 2010-10-14 18:55:27

+0

@mathtick“I幻想这可能是通过使用UNIX来运行代码来跟踪文件访问的方式。“这是绝对可能的,使用'strace'来解决这个问题是你需要真正运行代码(动态vs静态分析),你不会看到所有可能的命令/文件 - 只有那些在执行/访问期间这个特殊的运行 – 2010-10-14 19:40:03

+0

谢谢,这看起来是一个很好的起点,ptree和pfiles的组合也许是动态分析的一个有用的起点,测试所有的情况(而不仅仅是那些碰巧运行在特定实例)对于我现在看到的代码来说非常重要 – mathtick 2010-10-15 14:46:10

5

您可以使用'strace'来运行脚本并查看脚本及其子进程的所有内容,包括查找和打开文件。例如:

$ cat foo.sh 
#!/usr/bin/env bash 

touch /tmp/foon 
$ chmod +x foo.sh 
$ strace -f -e execve,access,open,stat -o foo.trace ./foo.sh 
$ cat foo.trace 
32176 execve("./foo.sh", ["./foo.sh"], [/* 42 vars */]) = 0 
32176 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) 
32176 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) 
32176 open("/usr/local/lib/tls/x86_64/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) 
... 
32176 execve("/bin/bash", ["bash", "./foo.sh"], [/* 42 vars */]) = 0 
... 
32177 execve("/usr/bin/touch", ["touch", "/tmp/foon"], [/* 41 vars */]) = 0 
32177 open("/tmp/foon", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 3 
... 
32176 --- SIGCHLD (Child exited) @ 0 (0) --- 
$ 

我修剪了很多其他活动(开放系统库;查找语言环境数据等等)。查看“man strace”以了解选项的含义。 -f,-o和-e是我经常使用的。

+0

这对于显示脚本的执行路径很有帮助,但理想情况下OP的问题的解决方案也会显示未执行的路径(类似于怎么'bash -n'在整个脚本中检查语法) – 2010-11-10 03:48:51

+0

是的,这对我来说有点问题......有很多例外情况发送脚本来访问不同的文件, d令人难以置信。我的主要策略是使用strace并减少输出,以便我可以运行差异来查看事情何时发生急剧变化。 – mathtick 2010-11-10 15:08:23

0

你只是不能用这样一种动态语言来做到这一点,你的静态分析工具将不可靠,并会错过一些依赖关系。考虑下面的代码:

#!/bin/sh 

func_foo() { echo 'foo running' ; } 
func_bar() { echo 'bar running' ; } 
# etc... 

printf 'foo, bar,...? ' # for testing 
read RPC 
# rpc_is_in_rpclist "$RPC" || die "invalid call" 
printf 'Calling func_%s\n' "$RPC" 
func_"$RPC" 

这不是一个复杂的例子;我最近通过参数向生产环境中添加了更详细的版本。

如果你真的需要静态分析,那么你不应该使用在首位动态语言,他们只是彼此不兼容。对于函数作为参数传递的其他函数式语言也是如此:静态分析实际上不能预测参数的值。

即使在像Java这样非常静态和简单的语言中,如果您努力尝试并使用反射,仍然可以躲避静态分析。然而,由于反射设计繁琐且不被广泛使用,因此对Java的分析在实践中非常有用:请参阅Eclipse等。

+0

的确,你想要一个分析工具来处理你所显示的代码,但这不是一个好的设计。为了可维护性等,应该使用'case'语句。 – 2010-11-11 01:06:31

+0

@Dennis:人们使用动态语言的一个原因是因为他们可以更快地编码*。为此,他们准备在编译时承担较少的静态分析/验证风险。要实际执行得更快,许多脚本不会受到重量级的病例陈述的困扰。否则,他们的开发人员会使用更静态的语言。 – MarcH 2010-11-11 09:33:14