简体   繁体   English

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

[英]How to get list of commands used in a shell script?

I have a shell script of more than 1000 lines, i would like to check if all the commands used in the script are installed in my Linux operating system.我有一个超过 1000 行的 shell 脚本,我想检查脚本中使用的所有命令是否都安装在我的 Linux 操作系统中。 Is there any tool to get the list of Linux commands used in the shell script?是否有任何工具可以获取 shell 脚本中使用的 Linux 命令列表? Or how can i write a small script which can do this for me?或者我如何编写一个可以为我完成此操作的小脚本?

The script runs successfully on the Ubuntu machine, it is invoked as a part of C++ application.该脚本在 Ubuntu 机器上成功运行,它作为 C++ 应用程序的一部分被调用。 we need to run the same on a device where a Linux with limited capability runs.我们需要在运行功能有限的 Linux 的设备上运行相同的程序。 I have identified manually, few commands which the script runs and not present on Device OS.我已经手动确定了脚本运行的几个命令,但设备操作系统上不存在这些命令。 before we try installing these commands i would like to check all other commands and install all at once.在我们尝试安装这些命令之前,我想检查所有其他命令并立即安装。

Thanks in advance提前致谢

I already tried this in the past and got to the conclusion that is very difficult to provide a solution which would work for all scripts.我过去已经尝试过这个并得出结论,很难提供一个适用于所有脚本的解决方案。 The reason is that each script with complex commands has a different approach in using the shells features.原因是每个具有复杂命令的脚本在使用 shell 功能时都有不同的方法。 In case of a simple linear script, it might be as easy as using debug mode.如果是简单的线性脚本,可能就像使用调试模式一样简单。 For example: bash -x script.sh 2>&1 | grep ^+ | awk '{print $2}' | sort -u例如: bash -x script.sh 2>&1 | grep ^+ | awk '{print $2}' | sort -u bash -x script.sh 2>&1 | grep ^+ | awk '{print $2}' | sort -u bash -x script.sh 2>&1 | grep ^+ | awk '{print $2}' | sort -u In case the script has some decisions, then you might use the same approach an consider that for the "else" cases the commands would still be the same just with different arguments or would be something trivial (echo + exit). bash -x script.sh 2>&1 | grep ^+ | awk '{print $2}' | sort -u如果脚本有一些决定,那么您可以使用相同的方法,并考虑到对于“其他”情况,命令仍然是相同的,只是参数不同,或者是微不足道的(echo + exit)。

In case of a complex script, I attempted to write a script that would just look for commands in the same place I would do it myself.在复杂脚本的情况下,我尝试编写一个脚本,它只会在我自己做的同一个地方寻找命令。 The challenge is to create expressions that would help identify all used possibilities, I would say this is doable for about 80-90% of the script and the output should only be used as reference since it will contain invalid data (~20%).挑战在于创建有助于识别所有使用可能性的表达式,我会说这对于大约 80-90% 的脚本是可行的,并且输出应仅用作参考,因为它将包含无效数据(~20%)。

Here is an example script that would parse itself using a very simple approach (separate commands on different lines, 1st word will be the command):这是一个示例脚本,它将使用非常简单的方法(不同行上的单独命令,第一个字将是命令)解析自身:

# 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

the output is:输出是:

.
/
/g.
awk
cat
sed
sort
tr

There are many more cases to consider (command substitutions, aliases etc.), 1, 2 and 3 are just beginning, but they would still cover 80% of most complex scripts.还有更多情况需要考虑(命令替换、别名等),1、2 和 3 才刚刚开始,但它们仍将涵盖 80% 的最复杂脚本。 The regular expressions used would need to be adjusted or extended to increase precision and special cases.使用的正则表达式需要调整或扩展以提高精度和特殊情况。

In conclusion if you really need something like this, then you can write a script as above, but don't trust the output until you verify it yourself.总之,如果你真的需要这样的东西,那么你可以像上面那样编写脚本,但在你自己验证之前不要相信输出。

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

If you have a fedora/redhat based system, bash has been patched with the --rpm-requires flag如果你有一个基于 fedora/redhat 的系统, bash已经用--rpm-requires标志打了补丁

--rpm-requires : Produce the list of files that are required for the shell script to run. --rpm-requires生成运行 shell 脚本所需的文件列表。 This implies -n and is subject to the same limitations as compile time error checking checking;这意味着-n并且受到与编译时错误检查相同的限制; Command substitutions, Conditional expressions and eval builtin are not parsed so some dependencies may be missed.命令替换、条件表达式和eval内置eval没有被解析,因此可能会遗漏一些依赖项。

So when you run the following:因此,当您运行以下命令时:

$ bash --rpm-requires script.sh
executable(command1)
function(function1)
function(function2)
executable(command2)
function(function3)

There are some limitations here:这里有一些限制:

  1. command and process substitutions and conditional expressions are not picked up.命令和进程替换以及条件表达式不会被选取。 So the following are ignored:因此忽略以下内容:

     $(command) <(command) >(command) command1 && command2 || command3
  2. commands as strings are not picked up.命令作为字符串不会被拾取。 So the following line will be ignored所以以下行将被忽略

    "/path/to/my/command"
  3. commands that contain shell variables are not listed.未列出包含 shell 变量的命令。 This generally makes sense since some might be the result of some script logic, but even the following is ignored这通常是有道理的,因为有些可能是某些脚本逻辑的结果,但即使是以下内容也被忽略

    $HOME/bin/command

    This point can however be bypassed by using envsubst and running it as但是,可以通过使用envsubst并将其作为

    $ bash --rpm-requires <(<script envsubst)

    However, if you use shellcheck, you most likely quoted this and it will still be ignored due to point 2但是,如果您使用 shellcheck,您很可能引用了这一点,但由于第 2 点,它仍将被忽略

So if you want to use check if your scripts are all there, you can do something like:因此,如果您想使用检查脚本是否全部存在,您可以执行以下操作:

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

If your script contains files that are sourced that might contain various functions and other important definitions, you might want to do something like如果您的脚本包含可能包含各种函数和其他重要定义的源文件,您可能需要执行以下操作

bash --rpm-requires <(cat source1 source2 ... <(<script.sh envsubst))  

Based @czvtools' answer , I added some extra checks to filter out bad values:基于@czvtools 的回答,我添加了一些额外的检查来过滤掉错误的值:

#!/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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM