如何验证程序是否存在,以返回错误并退出,或继续执行脚本?

看起来应该很容易,但这让我很为难。


当前回答

如果没有任何可用的外部类型命令(在这里是理所当然的),我们可以使用符合POSIX的env-i sh-c“type cmd 1>/dev/null 2>&1”:

# Portable version of Bash's type -P cmd (without output on stdout)
typep() {
   command -p env -i PATH="$PATH" sh -c '
      export LC_ALL=C LANG=C
      cmd="$1"
      cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
      [ $? != 0 ] && exit 1
      case "$cmd" in
        *\ /*) exit 0;;
            *) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
      esac
   ' _ "$1" || exit 1
}

# Get your standard $PATH value
#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp

至少在Mac OS X v10.6.8(雪豹)上,使用Bash 4.2.24(2)命令-vls与移动的/bin/ls温度不匹配。

其他回答

我想说,由于悬挂别名,没有任何可移植和100%可靠的方法。例如:

alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/

当然,只有最后一个是有问题的(林戈没有冒犯!)。但从command-v的角度来看,它们都是有效的别名。

为了拒绝像ringo这样的悬空命令,我们必须解析shell内置别名命令的输出并递归到它们中(这里命令-v并不优于别名)。没有任何可移植的解决方案,即使是特定于Bash的解决方案也相当乏味。

注意,类似这样的解决方案将无条件拒绝别名ls='ls-F':

test() { command -v $1 | grep -qv alias }

对于感兴趣的人来说,如果您希望检测已安装的库,则前面的答案中的方法都不起作用。我想你要么要检查路径(可能是头文件之类的),要么就这样(如果你是基于Debian的发行版):

dpkg --status libdb-dev | grep -q not-installed

if [ $? -eq 0 ]; then
    apt-get install libdb-dev
fi

从上面可以看到,查询中的“0”表示未安装包。这是“grep”的函数-“0”表示找到匹配项,“1”表示没有找到匹配项。

我在.bashrc中定义了一个函数,这使得这更容易。

command_exists () {
    type "$1" &> /dev/null ;
}

下面是一个如何使用它的示例(来自我的.bash_profile)

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi

扩展@lhunath和@GregV的答案,下面是那些希望将该检查轻松放入if语句的人的代码:

exists()
{
  command -v "$1" >/dev/null 2>&1
}

以下是使用方法:

if exists bash; then
  echo 'Bash exists!'
else
  echo 'Your system does not have Bash'
fi

如果你的男人/女孩不能在这里得到答案中的东西,并且你的头发从你的背部,尝试使用bash-c运行相同的命令。看看这个梦游性谵妄。这是运行$(子命令)时真正发生的情况:

第一它可以给你完全不同的输出。

$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls

第二它根本不会给你任何输出。

$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found