如何在bash脚本中检查依赖关系

11

我想检查系统上是否安装了nodejs。 我收到以下错误:

错误:未找到命令。

该如何解决?

#!/bin/bash

if [ nodejs -v ]; then
echo "nodejs found"
else
echo "nodejs not found"
fi
6个回答

23
你可以使用 Bash 内置的 `command` 命令:command
if command -v nodejs >/dev/null 2>&1 ; then
    echo "nodejs found"
    echo "version: $(nodejs -v)"
else
    echo "nodejs not found"
fi

1
检查help command以获取正确的文档,因为它是一个shell内置命令。顺便说一句,现在我可能会建议使用type内置命令,因为它有更多选项来包含/排除函数和别名。 - hek2mgl
我一直在尝试使用 help,但我的 shell 找不到它。刚才我意识到我实际上一直在尝试在 zsh 中使用它。感谢澄清。我一直在使用 type 内置命令,但现在切换到了 command,因为这是这里最受欢迎的(没有明确的最佳实践)。我想我会切换回 type。如果您能在答案中更新关于 type 的评论,那还好吗?或者这并不是很重要? - Fanatique
这段内容并不适合放在这篇文章中,因为原帖的问题是如何检查他们的操作系统上是否安装了nodejs。command是这里正确的工具,因为它不包括shell函数。(type -f也可以工作,但它更加复杂) - hek2mgl

2
这不是OP(原帖发布者)近3年前所要求的,但对于任何想要检查多个依赖项的人来说,以下内容可能有用:
#!/bin/bash
echo -n "Checking dependencies... "
for name in youtube-dl yad ffmpeg
do
  [[ $(which $name 2>/dev/null) ]] || { echo -en "\n$name needs to be installed. Use 'sudo apt-get install $name'";deps=1; }
done
[[ $deps -ne 1 ]] && echo "OK" || { echo -en "\nInstall the above and rerun this script\n";exit 1; }

这是它的工作原理。首先,我们打印一行文字,说明我们正在检查依赖项。第二行开始一个“for name in…”循环,其中我们放置我们想要检查的依赖项,在此示例中,我们将检查youtube-dl、yad和ffmpeg。循环开始(使用“do”),下一行使用bash命令“which”检查每个命令是否存在。如果该依赖项已安装,则不执行任何操作并跳过循环中的下一个命令。如果确实需要安装它,则会打印消息并设置变量“deps”为1(deps = dependencies),然后继续检查下一个命令。检查完所有命令后,最后一行通过检查deps变量来检查是否需要任何依赖项。如果未设置,则在最初说“正在检查依赖项...”的行尾附加“OK”,并继续执行脚本的其余部分(假设这是脚本的第一部分)。如果已设置,则打印一条消息,要求安装依赖项并重新运行脚本。然后退出脚本。
echo命令看起来很复杂,但它们是为了在终端上提供干净的输出而必要的。以下是屏幕截图,显示第一次运行时未满足依赖项,但第二次运行时满足了依赖项。

Bash dependency check script screen print

如果您将此保存为脚本,您需要在与脚本相同的目录中,并键入 ./{name_of_your_script},并且它需要可执行权限。

1
不要在脚本中使用 which - Leonhardt Wille
4
@Leonhardt Wille - 这是一个非常棒的社区,大家可以从中学到很多东西。没有解释、原因或建议就发表诸如“不要在脚本中使用which”这样的陈述并没有为帖子增加任何有用的信息。我看到你在另一篇帖子中也发表了完全相同的评论。我猜想你指的是which的可移植性较差。然而,在bash中,注意到我的示例在第一行指定了#!/bin/bash,它会忽略具有相同名称的内置命令或函数的缺陷。OP想知道某个命令是否已安装。我的脚本正好做到了这一点。 - Scooby-2
1
对于任何想知道避免使用 which 的确切原因的人(比如我自己),这里有更多信息:https://dev59.com/2nRB5IYBdhLWcg3wiHv7 - Alex W

2
命令的名称是node,而不是nodejs。如果存在,则返回该命令的路径到标准输出(stdout)。
if [ $(which node 2>/dev/null) ]; then
  echo "nodejs found"
else
  echo "nodejs not found"
fi

不要在脚本中使用 which - Leonhardt Wille
1
对于任何想知道避免使用 which 的确切原因的人(比如我自己),这里有更多信息:https://dev59.com/2nRB5IYBdhLWcg3wiHv7 - Alex W

1

您可以通过以下方式检查程序或函数是否存在:

type nodejs &>/dev/null || echo "node js not installed"

然而,这里有一个更复杂的解释 在这里 可供参考。

0
我在思考这个问题并想出了几个版本,然后上网查看了其他人的意见,最终来到了这里。虽然这是一个旧帖子,但我会回复我的想法。
首先回答原帖提出的问题:如何修复它?
if node -v &>/dev/null; then
    echo "nodejs found"
else
    echo "nodejs not found"
fi

如果您只是想检查节点是否工作,这个方法可以。但这并不是一个非常通用的方法。
另一种方法是使用循环中的命令,并收集缺少的依赖项(在此示例中查找命令kindkubectl)。
for app in kind kubectl; do command -v "${app}" &>/dev/null || not_available+=("${app}"); done
(( ${#not_available[@]} > 0 )) && echo "Please install missing dependencies: ${not_available[*]}" 1>&2 && exit 1

或者更不简洁地表达:

unset not_available # script safety, however not necessary.

for app in kind kubectl; do
    if ! command -v "${app}" &>/dev/null; then
        not_available+=("${app}")
    fi
done

if (( ${#not_available[@]} > 0 )); then
    echo "Please install missing dependencies: ${not_available[@]}" 1>&2
    exit 1
fi

然后我想要一种不需要循环就能做到同样效果的方法,于是想出了这个:

not_installed=$(command -V kind kubectl 2>&1 | awk -F': +' '$NF == "not found" {printf "%s ", $(NF-1)}')
[[ -n ${not_installed} ]] && echo "Please install missing dependencies: ${not_installed}" 1>&2 && exit 1

command -V 可以接受任意数量的条目,并将结果返回到 stdout 和 stderr(尽管我将两者都重定向到 stdout 以供下一个命令解析)。

awk 将字段分隔符设置为 <冒号><一个或多个空格>,表示为 : +。如果最后一个字段包含 "not found",则打印倒数第二个字段,即未安装的命令的名称。

最后,如果变量包含任何数据,则报告缺少哪些依赖项到 stderrexit 脚本!


你可以以无数种方式进行依赖性检查,但这里有几个更通用且不太冗长,同时易于遵循的替代方案。 :]


-1
如果你只是想检查一个命令是否存在,可以使用which命令。它会返回命令的路径,如果找不到则返回空。
if [ "$(which openssl)" = "" ] ;then
echo "This script requires openssl, please resolve and try again."
exit 1
fi

不要在脚本中使用 which - Leonhardt Wille
对于任何(像我一样)想知道避免使用 which 的确切原因的人,这里有更多的信息:https://dev59.com/2nRB5IYBdhLWcg3wiHv7 - Alex W

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接