如何检查Bash脚本中是否存在程序?

如何检查Bash脚本中是否存在程序?,bash,Bash,我如何验证程序是否存在,以返回错误并退出,或继续使用脚本的方式 看起来应该很简单,但这一直困扰着我。这个命令可能有用 如果找到可执行文件,则返回0;如果找不到或不可执行文件,则返回1: [ -x "$(command -v foo)" ] 名称 哪个-定位命令 提要 哪个[-a]文件名。。。 描述 它返回要创建的文件的路径名 在当前环境中执行,具有 参数作为命令以严格的形式给出 POSIX共形壳。它通过搜索来实现这一点 与名称匹配的可执行文件的路径 争论的焦点。 选择权 -a打印每个参数的所有

我如何验证程序是否存在,以返回错误并退出,或继续使用脚本的方式


看起来应该很简单,但这一直困扰着我。

这个
命令可能有用

如果找到可执行文件,则返回0;如果找不到或不可执行文件,则返回1:

[ -x "$(command -v foo)" ]
名称
哪个-定位命令
提要
哪个[-a]文件名。。。
描述
它返回要创建的文件的路径名
在当前环境中执行,具有
参数作为命令以严格的形式给出
POSIX共形壳。它通过搜索来实现这一点
与名称匹配的可执行文件的路径
争论的焦点。
选择权
-a打印每个参数的所有匹配路径名
退出状态
如果所有指定的命令都是
已找到并可执行
1如果一个或多个指定命令不存在
还是不可执行
2如果指定了无效选项
which
的好处在于,它可以确定运行在哪个
环境中的可执行文件是否可用-它可以避免一些问题…

尝试使用:

test -x filename

从下面的Bash手册页:


这取决于您是否想知道它是否存在于
$PATH
变量中的一个目录中,或者您是否知道它的绝对位置。如果您想知道它是否在
$PATH
变量中,请使用

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi
否则使用

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

在第一个示例中,重定向到
/dev/null/
会抑制
程序的输出。

如果可以:

which programname

答复 POSIX兼容:

command -v <the_command>
对于特定于Bash的环境:

hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
(次要提示:有些人会建议
2>&-
2>/dev/null
相同,但较短–这是不真实的。
2>&-
关闭FD 2,当程序尝试写入stderr时,会在程序中导致错误,这与成功写入并丢弃输出(非常危险!)截然不同

如果您的hash bang是
/bin/sh
,那么您应该关心POSIX所说的内容type
hash
的退出代码,并且当命令不存在时,
hash
可以成功退出(在
type
中还没有看到)<代码>命令
的退出状态由POSIX很好地定义,因此使用它可能是最安全的

但是,如果您的脚本使用
bash
,POSIX规则就不再重要了,
type
hash
都可以非常安全地使用
type
现在有一个
-P
来只搜索
路径
hash
的副作用是命令的位置将被散列(以便下次使用它时更快地查找),这通常是一件好事,因为您可能会检查它的存在以便实际使用它

作为一个简单的示例,这里有一个函数,如果存在,则运行
gdate
,否则运行
date

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}
具有完整功能集的备选方案 你可以用它来满足你的需要

要检查是否安装了某些设备,可以执行以下操作:

checkBin | | errorMessage“此工具需要。请安装它,然后再次运行此工具。”

在我有权使用的盒子上工作时,我从未得到过以前的答案。例如,安装了
类型
(执行所需操作)。因此需要内置指令。此命令适用于我:

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi

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


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

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

command_exists () {
    type "$1" &> /dev/null ;
}
下面是一个如何使用它的示例(来自我的
.bash\u配置文件


我同意Lhunah不鼓励使用
,而他的解决方案对Bash用户完全有效。但是,为了便于携带,应使用
命令-v

$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }
Command
Command
与POSIX兼容。有关其规格,请参见此处:


注意:
type
与POSIX兼容,但
type-p
不兼容。

我必须检查是否在部署服务器时安装了Git。我最后的Bash脚本如下(Ubuntu服务器):


为了模仿Bash的
type-pcmd
,我们可以使用与POSIX兼容的
env-i type cmd 1>/dev/null 2>&1

man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.

ls() { echo 'Hello, world!'; }

ls
type ls
env -i type ls

cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
要在Bash脚本中使用
哈希

hash foo &> /dev/null
if [ $? -eq 1 ]; then
    echo >&2 "foo not found."
fi
此脚本运行
hash
,然后检查最近命令的退出代码(存储在
$?
中的值)是否等于
1
。如果
hash
未找到
foo
,则退出代码将为
1
。如果存在
foo
,则退出代码将为
0


&>dev/null
重定向并从
散列
,这样它就不会出现在屏幕上,
echo>&2
将消息写入标准错误。

散列变量有一个陷阱:例如,可以在命令行上键入

one_folder/process

使过程得以执行。为此,one_文件夹的父文件夹必须位于$PATH中。但当您尝试对此命令进行哈希运算时,它将始终成功:

hash one_folder/process; echo $? # will always output '0'

如果您检查程序是否存在,您可能会稍后再运行它。为什么不先试着运行它呢

if foo --version >/dev/null 2>&1; then
    echo Found
else
    echo Not found
fi
与仅仅查看路径目录和f相比,程序运行时的检查更可靠
$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }
if ! builtin type -p git &>/dev/null; then
  sudo apt-get -y install git-core
fi
man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.

ls() { echo 'Hello, world!'; }

ls
type ls
env -i type ls

cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
hash foo &> /dev/null
if [ $? -eq 1 ]; then
    echo >&2 "foo not found."
fi
one_folder/process
hash one_folder/process; echo $? # will always output '0'
if foo --version >/dev/null 2>&1; then
    echo Found
else
    echo Not found
fi
md=$(command -v mkdirhier) ; alias md=${md:=mkdir}  # bash

emacs="$(command -v emacs) -nw" || emacs=nano
alias e=$emacs
[[ -z $(command -v jed) ]] && alias jed=$emacs
for cmd in latex pandoc; do
  printf '%-10s' "$cmd"
  if hash "$cmd" 2>/dev/null; then
    echo OK
  else
    echo missing
  fi
done
latex     OK
pandoc    missing
[ -x "$(command -v foo)" ]
if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  exit 1
fi
# 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
function _apt_install() {
    apt-get install -y $1 > /dev/null
}

function _apt_install_norecommends() {
    apt-get install -y --no-install-recommends $1 > /dev/null
}
function _apt_available() {
    if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
        echo "Package is available : $1"
        PACKAGE_INSTALL="1"
    else
        echo "Package $1 is NOT available for install"
        echo  "We can not continue without this package..."
        echo  "Exitting now.."
        exit 0
    fi
}
function _package_install {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install $1
            sleep 0.5
        fi
    fi
}

function _package_install_no_recommends {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install_norecommends $1
            sleep 0.5
        fi
    fi
}
$ 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
exists()
{
  command -v "$1" >/dev/null 2>&1
}
if exists bash; then
  echo 'Bash exists!'
else
  echo 'Your system does not have Bash'
fi
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
test() { command -v $1 | grep -qv alias }
# First check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
  echo "The time program does not exist on this system."
  exit 1
fi

# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt
[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }
test -x "$(which <command>)"
install:
    @if [[ ! -x "$(shell command -v ghead)" ]]; then \
        echo 'ghead does not exist. Please install it.'; \
        exit -1; \
    fi
#!/usr/bin/env bash                                                                
set -x                                                                             

# if local program 'foo' returns 1 (doesn't exist) then...                                                                               
if ! type -P foo; then                                                             
    echo 'crap, no foo'                                                            
else                                                                               
    echo 'sweet, we have foo!'                                                    
fi                                                                                 
THE ZSH/PARAMETER MODULE
       The zsh/parameter module gives access to some of the internal hash  ta‐
       bles used by the shell by defining some special parameters.


[...]

       commands
              This  array gives access to the command hash table. The keys are
              the names of external commands, the values are the pathnames  of
              the  files  that would be executed when the command would be in‐
              voked. Setting a key in this array defines a new entry  in  this
              table  in the same way as with the hash builtin. Unsetting a key
              as in `unset "commands[foo]"' removes the entry  for  the  given
              key from the command hash table.

martin@martin ~ % echo $commands[zsh]
/usr/bin/zsh
if (( ${+commands[zsh]} ))
then
  echo "zsh is available"
fi
if (( ${+commands[zsh]} )) && [[ -x $commands[zsh] ]]
then
  echo "zsh is available"
fi