如何获取shell脚本中使用的命令列表?

kxxlusnw  于 2023-10-23  发布在  Shell
关注(0)|答案(4)|浏览(138)

我有一个超过1000行的shell脚本,我想检查脚本中使用的所有命令是否都安装在我的Linux操作系统中。有没有工具可以获取shell脚本中使用的Linux命令列表?我怎么能写一个小的脚本,可以为我做这件事?
该脚本在Ubuntu机器上成功运行,它作为C++应用程序的一部分被调用。我们需要在一个运行能力有限的Linux的设备上运行相同的程序。我已经确定手动,脚本运行的几个命令,不存在于设备操作系统.在我们尝试安装这些命令之前,我想检查所有其他命令并一次性安装。
Thanks in advance

7tofc5zh

7tofc5zh1#

基于@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))
        continue
    end

    # There may be things like:
    #   PATCH_STRING=$(zypper
    #   REPOS=$(zypper
    set subshell_command (string split -f2 '=$(' -- $command)
    if test -n "$subshell_command" && command -q -- $subshell_command
        set -a resolved (realpath (which $subshell_command))
        continue
    end
end

set resolved (string join0 $resolved | sort -z -u | string split0)

for command in $resolved
    echo $command
end
bgibtngc

bgibtngc2#

我在过去已经尝试过了,并且得出的结论是很难提供一个适用于所有脚本的解决方案。原因是每个带有复杂命令的脚本在使用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%的最复杂的脚本。需要调整或扩展所使用的正则表达式,以提高精度和特殊情况。
总之,如果你真的需要这样的东西,那么你可以写一个脚本如上所述,但不要相信输出,直到你自己验证它。

zzzyeukh

zzzyeukh3#

1.将export PATH=''添加到脚本的第二行。
1.执行your_script.sh 2>&1 > /dev/null | grep 'No such file or directory' | awk '{print $4;}' | grep -v '/' | sort | uniq | sed 's/.$//'

k97glaaz

k97glaaz4#

如果您有一个基于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)

这里有一些限制:
1.不拾取命令和过程替换以及条件表达式。因此,以下内容将被忽略:

$(command)
<(command)
>(command)
command1 && command2 || command3

1.字符串形式的命令不被拾取。因此下面的行将被忽略

"/path/to/my/command"

1.不列出包含shell变量的命令。这通常是有意义的,因为有些可能是某些脚本逻辑的结果,但即使是以下内容也会被忽略

$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))

相关问题