如何检查shell脚本中是否存在命令?

我正在编写我的第一个shell脚本。在我的脚本中,我想检查某个命令是否存在,如果不存在,安装可执行文件。如何检查该命令是否存在?

if # Check that foobar command doesnt exist
then
# Now install foobar
fi
170535 次浏览

尝试使用type:

type foobar

例如:

$ type ls
ls is aliased to `ls --color=auto'


$ type foobar
-bash: type: foobar: not found

这比which更可取,原因如下:

  1. 默认的which实现只支持显示所有选项的-a选项,所以你必须找到一个支持别名的替代版本

  2. type将确切地告诉你你在看什么(它是一个Bash函数或别名或适当的二进制)。

  3. type不需要子进程

  4. type不能被二进制文件掩盖(例如,在Linux机器上,如果你创建了一个名为which的程序,它出现在路径中真正的which之前,事情就会发生。另一方面,type是一个内置的shell(是的,一个下属无意中做了一次)。

which <cmd>

如果适用于你的情况,也可以查看options which支持中的别名。

例子

$ which foobar
which: no foobar in (/usr/local/bin:/usr/bin:/cygdrive/c/Program Files (x86)/PC Connectivity Solution:/cygdrive/c/Windows/system32/System32/WindowsPowerShell/v1.0:/cygdrive/d/Program Files (x86)/Graphviz 2.28/bin:/cygdrive/d/Program Files (x86)/GNU/GnuPG
$ if [ $? -eq 0 ]; then echo "foobar is found in PATH"; else echo "foobar is NOT found in PATH, of course it does not mean it is not installed."; fi
foobar is NOT found in PATH, of course it does not mean it is not installed.
$

PS:注意不是所有安装的东西都在PATH中。通常,为了检查某些东西是否“安装”,人们会使用与操作系统相关的安装相关命令。例如:RHEL的rpm -qa | grep -i "foobar"

一般来说,这取决于你的shell,但如果你使用bash, zsh, ksh或sh(由dash提供),下面应该工作:

if ! type "$foobar_command_name" > /dev/null; then
# install foobar here
fi

对于一个真实的安装脚本,你可能想要确保在存在别名foobar的情况下type不会成功返回。在bash中,你可以这样做:

if ! foobar_loc="$(type -p "$foobar_command_name")" || [[ -z $foobar_loc ]]; then
# install foobar here
fi

检查Bash脚本中是否存在一个程序很好地涵盖了这一点。在任何shell脚本中,你最好运行command -v $command_name来测试$command_name是否可以运行。在bash中,你可以使用hash $command_name,它也会对任何路径查找的结果进行散列,如果你只想看到二进制文件(而不是函数等),可以使用type -P $binary_name

这个问题没有指定shell,所以对于那些使用fish(友好的交互式shell)的人:

if command -v foo > /dev/null
echo exists
else
echo does not exist
end

为了基本的POSIX兼容性,我们使用-v标志,它是--search-s的别名。

5种方法,4个用于bash, 1个用于zsh:

  • type foobar &> /dev/null
  • hash foobar &> /dev/null
  • command -v foobar &> /dev/null
  • which foobar &> /dev/null
  • (( $+commands[foobar] ))(仅zsh)

你可以把它们中的任何一个放到if子句中。根据我的测试(https://www.topbug.net/blog/2016/10/11/speed-test-check-the-existence-of-a-command-in-bash-and-zsh/),在速度方面,bash中推荐第1和第3种方法,zsh中推荐第5种方法。

我在安装脚本中为此制作的函数

function assertInstalled() {
for var in "$@"; do
if ! which $var &> /dev/null; then
echo "Install $var!"
exit 1
fi
done
}

示例调用:

assertInstalled zsh vim wget python pip git cmake fc-cache

在bash和zsh中都可以工作的函数:

# Return the first pathname in $PATH for name in $1
function cmd_path () {
if [[ $ZSH_VERSION ]]; then
whence -cp "$1" 2> /dev/null
else  # bash
type -P "$1"  # No output if not in $PATH
fi
}

如果在$PATH中没有找到该命令,则返回非零。