如何检查命令是不是存在于 shell 脚本中? [复制]
Posted
技术标签:
【中文标题】如何检查命令是不是存在于 shell 脚本中? [复制]【英文标题】:How can I check if a command exists in a shell script? [duplicate]如何检查命令是否存在于 shell 脚本中? [复制] 【发布时间】:2011-11-23 06:37:19 【问题描述】:我正在编写我的第一个 shell 脚本。在我的脚本中,我想检查某个命令是否存在,如果不存在,请安装可执行文件。如何检查此命令是否存在?
if # Check that foobar command doesnt exist
then
# Now install foobar
fi
【问题讨论】:
刚好碰到。我认为这是同一个问题:***.com/questions/592620/…,但它提供了更多细节。 @JerryTian 感谢您的链接 同样相关的是How to 'hash -r' and refresh all shells? 和When to rehash executables in $PATH with bash? 这不是“已经回答”,因为它询问的是 shell 脚本,这至少意味着sh
,而所提到的问题特定于 bash
。
【参考方案1】:
尝试使用type
:
type foobar
例如:
$ type ls
ls is aliased to `ls --color=auto'
$ type foobar
-bash: type: foobar: not found
这比which
更可取,原因如下:
默认的which
实现仅支持显示所有选项的-a
选项,因此您必须找到支持别名的替代版本
type
会准确告诉您正在查看的内容(无论是 Bash 函数、别名还是适当的二进制文件)。
type
不需要子进程
type
不能被二进制文件屏蔽(例如,在 Linux 机器上,如果您创建一个名为 which
的程序,该程序出现在真正的 which
之前的路径中,事情就很糟糕了。@另一方面,987654332@ 是一个内置的 shell(是的,一个下属无意中这样做了一次)。
【讨论】:
你能把它放在 if/else 语句的形式(不输出到控制台)吗? 而在某些自定义 Linux 上,没有 ''which'' 命令。【参考方案2】:which <cmd>
如果适用于您的情况,另请参阅 options which
supports 获取别名。
例子
$ 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 中。通常要检查是否“安装”了某些东西,会使用与操作系统相关的安装相关命令。例如。 rpm -qa | grep -i "foobar"
用于 RHEL。
【讨论】:
which
还有其他陷阱
我刚开始阅读 man type
以了解它如何更好。也许你可以在这里发布它来节省我一些时间.. :)
which
的真正问题在于它是一个 external 命令,无法处理当前 shell 会话内部的细节,因为它对他们一无所知。
Check if a program exists from a Bash script 特别建议不要使用which
。
这里最好不要使用which,其他答案更安全【参考方案3】:
一般来说,这取决于您的 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
【讨论】:
我喜欢这个答案。我尽量不被我更喜欢的ivants形象所左右;) hmm...当我将其更改为if ! type "foo" > /dev/null;
时,我会在屏幕上看到输出“myscript.sh: line 12: type: foo: not found”,但是,它似乎仍然存在工作,因为当我说if ! type "ls" > /dev/null;
时没有输出并且 if 语句没有被执行(因为它返回 true)。当命令不存在时如何使输出静音?
安德鲁,试试if ! type "foo" > /dev/null 2>&1;
> /dev/null 2>&1
与&> /dev/null
相同
type
的手册页在我的发行版(Arch Linux)上非常糟糕。帮助文本更好,尽管只有一点点。 type: usage: type [-afptP] name [name ...]
。手册页将“选项”显示为“无”。【参考方案4】:
Check if a program exists from a Bash script 很好地涵盖了这一点。在任何 shell 脚本中,您最好运行 command -v $command_name
来测试是否可以运行 $command_name
。在 bash 中,您可以使用 hash $command_name
,它还会对任何路径查找的结果进行散列处理;如果您只想查看二进制文件(而不是函数等),则可以使用 type -P $binary_name
【讨论】:
【参考方案5】:问题没有指定外壳,所以对于那些使用 fish(友好的交互式外壳)的人:
if command -v foo > /dev/null
echo exists
else
echo does not exist
end
为了基本的 POSIX 兼容性,我们使用 -v
标志,它是 --search
或 -s
的别名。
【讨论】:
不适用于别名 @Herrgott 那是因为command -v/-s
在$PATH
中搜索。 fish中的别名是函数,函数在$fish_function_path
中搜索。检查别名是否存在的许多方法,例如if alias | grep -w 'myalias' >/dev/null; echo ok; end
.
这不是也执行命令吗?
@AaronFranke 它只搜索可执行文件,不执行它。
您可以使用--query
并避免重定向:fishshell.com/docs/current/cmds/command.html。虽然不符合 POSIX,但 command
内置在 Fish 中。【参考方案6】:
五种方式,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 种速度。
【讨论】:
Check if a program exists from a Bash script 特别建议不要使用which
。
还有 echo =foobar
在 zsh 中。请注意,您的 zsh
解决方案仅返回 true/false,但不打印路径名(如果存在)。如果foo
不存在,echo $commands[foo]
也不会返回非零值。有关在两个 shell 中都可以使用的功能,请参阅here
第五条命令在 macOS Catalina 中的 zsh
中不返回任何内容。 zsh
版本为zsh 5.7.1 (x86_64-apple-darwin19.0)
@Raptor if
检查退出代码。【参考方案7】:
我在安装脚本中的一个功能正是为此而制作的
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
【讨论】:
注意:这会使 zsh 崩溃 只有在您在脚本之外调用它或获取脚本时才会崩溃。如果您这样做,请将出口 1 更改为返回 1 或其他一些错误代码。 Check if a program exists from a Bash script 特别建议不要使用which
。
我用过这个,但把which
改成了command -v
【参考方案8】:
一个在 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
中找不到该命令,则返回非零值。
【讨论】:
以上是关于如何检查命令是不是存在于 shell 脚本中? [复制]的主要内容,如果未能解决你的问题,请参考以下文章