我有一个超过1000行的shell脚本,我想检查脚本中使用的所有命令是否都安装在我的Linux操作系统中。 是否有任何工具可以获取shell脚本中使用的Linux命令列表? 或者我怎么能写一个可以为我做这个的小脚本?
该脚本在Ubuntu机器上成功运行,它作为C ++应用程序的一部分被调用。我们需要在运行具有有限功能的Linux的设备上运行相同的操作。我已手动识别,脚本运行的命令很少,而且设备操作系统上没有。在我们尝试安装这些命令之前,我想检查所有其他命令并立即安装所有命令。
提前致谢
答案 0 :(得分:1)
我过去已经尝试过这个并得出结论,很难提供适用于所有脚本的解决方案。原因是每个具有复杂命令的脚本在使用shell功能时都有不同的方法。
如果是简单的线性脚本,它可能就像使用调试模式一样简单。
例如:bash -x script.sh 2>&1 | grep ^+ | awk '{print $2}' | sort -u
如果脚本有一些决定,那么你可以使用相同的方法,考虑到对于“else”情况,命令对于不同的参数仍然是相同的,或者是微不足道的(echo + exit)。
如果是一个复杂的脚本,我试图编写一个脚本,只在我自己做的同一个地方寻找命令。挑战是创建有助于识别所有使用的可能性的表达式,我想这对于大约80-90%的脚本是可行的,并且输出应该仅用作参考,因为它将包含无效数据(~20%)。
这是一个示例脚本,它将使用一种非常简单的方法解析自身(不同行上的单独命令,第一个单词将是命令):
# 1. Eliminate all quoted text
# 2. Eliminate all comments
# 3. Replace all delimiters between commands with new lines ( ; | && || )
# 4. extract the command from 1st column and print it once
cat $0 \
| sed -e 's/\"/./g' -e "s/'[^']*'//g" -e 's/"[^"]*"//g' \
| sed -e "s/^[[:space:]]*#.*$//" -e "s/\([^\\]\)#[^\"']*$/\1/" \
| sed -e "s/&&/;/g" -e "s/||/;/g" | tr ";|" "\n\n" \
| awk '{print $1}' | sort -u
输出是:
.
/
/g.
awk
cat
sed
sort
tr
还有更多需要考虑的案例(命令替换,别名等),1,2和3才刚刚开始,但它们仍将涵盖80%的大多数复杂脚本。 使用的正则表达式需要调整或扩展,以提高精度和特殊情况。
总之,如果您确实需要这样的东西,那么您可以编写如上所述的脚本,但在您自己验证之前不要相信输出。
答案 1 :(得分:0)
export PATH=''
添加到脚本的第二行。your_script.sh 2>&1 > /dev/null | grep 'No such file or directory' | awk '{print $4;}' | grep -v '/' | sort | uniq | sed 's/.$//'
。答案 2 :(得分:0)
如果您使用的是基于fedora / redhat的系统,则bash
已使用--rpm-requires
标志进行了修补
--rpm-requires
::生成运行Shell脚本所需的文件列表。这意味着-n
并受到与编译时错误检查检查相同的限制; 未解析命令替换,条件表达式和内置eval
,因此可能会丢失某些依赖项。
因此,当您运行以下命令时:
$ bash --rpm-requires script.sh
executable(command1)
function(function1)
function(function2)
executable(command2)
function(function3)
这里有一些限制:
命令和进程替换以及条件表达式。因此,以下内容将被忽略:
$(command)
<(command)
>(command)
command1 && command2 || command3
命令作为字符串。因此,以下行将被忽略
"/path/to/my/command"
命令未列出。这通常是有道理的,因为 有些可能是某些脚本逻辑的结果,但即使以下内容也被忽略
$HOME/bin/command
不过,可以通过使用envsubst
并将其运行为
$ bash --rpm-requires <(<script envsubst)
但是,如果您使用shellcheck,则很可能引用了它,由于第2点,它仍将被忽略
因此,如果要使用检查脚本是否全部存在,可以执行以下操作:
while IFS='' read -r app; do
[ "${app%%(*}" == "executable" ] || continue
app="${app#*(}"; app="${app%)}";
if [ "$(type -t "${app}")" != "builtin" ] && \
! [ -x "$(command -v "${app}")" ]
then
echo "${app}: missing application"
fi
done < <(bash --rpm-requires <(<"$0" envsubst) )
如果您的脚本包含的源文件可能包含各种功能和其他重要定义,则您可能想要执行类似的操作
bash --rpm-requires <(cat source1 source2 ... <(<script.sh envsubst))
答案 3 :(得分:0)
基于@czvtools 的 answer,我添加了一些额外的检查来过滤掉错误的值:
#!/usr/bin/fish
if test "$argv[1]" = ""
echo "Give path to command to be tested"
exit 1
end
set commands (cat $argv \
| sed -e 's/\"/./g' -e "s/'[^']*'//g" -e 's/"[^"]*"//g' \
| sed -e "s/^[[:space:]]*#.*\$//" -e "s/\([^\\]\)#[^\"']*\$/\1/" \
| sed -e "s/&&/;/g" -e "s/||/;/g" | tr ";|" "\n\n" \
| awk '{print $1}' | sort -u)
for command in $commands
if command -q -- $command
set -a resolved (realpath (which $command))
end
end
set resolved (string join0 $resolved | sort -z -u | string split0)
for command in $resolved
echo $command
end