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

How to check if command exists in a shell script?

本问题已经有最佳答案,请猛点这里访问。

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

1
2
3
4
if #check that foobar command doesnt exist
then
    #now install foobar
fi


一般来说,这取决于您的shell,但是如果您使用bash、zsh、ksh或sh(如dash所提供),则以下内容应该有效:

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

对于真正的安装脚本,您可能希望确保在存在别名foobar的情况下,type不会成功返回。在bash中,您可以这样做:

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


尝试使用type

1
type foobar

例如:

1
2
3
4
5
$ type ls
ls is aliased to `ls --color=auto'

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

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

1)默认的which实现只支持显示所有选项的-a选项,因此您必须找到支持别名的替代版本。

2)类型将准确地告诉您正在查看的内容(可能是bash函数、别名或适当的二进制文件)。

3)类型不需要子进程

4)不能用二进制文件屏蔽类型(例如,在Linux设备上,如果您创建了一个名为which的程序,该程序出现在实际which之前的路径中,那么风扇就会受到影响。另一方面,type是一个内置的shell[是的,一个下属无意中做了一次]


五种方式,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种方法。


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


这个问题没有指定外壳,因此对于使用fish(友好的交互式外壳)的用户:

1
2
3
4
5
if command --search foo >/dev/null do
  echo exists
else
  echo does not exist
end

对于基本的POSIX兼容性,使用-v标志,它是--search-s的别名。


which

另请参见选项which支持别名(如果适用于您的案例)。

例子

1
2
3
4
5
$ 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.
$

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


同时在bash和zsh中工作的函数:

1
2
3
4
5
6
7
8
# 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中找不到该命令,则返回非零。


我在一个安装脚本中为这个做了一个函数

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

示例调用:

1
assertInstalled zsh vim wget python pip git cmake fc-cache