首页 > 解决方案 > 带感叹号的条件表达式仅适用于双括号

问题描述

我有一个安装工具的脚本,如果它不在我的系统上:

#!/bin/bash
ASCIIDOCTOR_BIN=`command -v asciidoctor`
if ! [ -x $ASCIIDOCTOR_BIN ]; then  ......

问题是,它似乎不起作用:条件表达式总是计算为false.

即使

#!/bin/bash
ASCIIDOCTOR_BIN=`command -v asciidoctor`
if ! [ false ]; then  ......

事实证明条件是错误的。

当我在玩它时,我发现如果我用双括号替换括号,它会起作用:

#!/bin/bash
ASCIIDOCTOR_BIN=`command -v asciidoctor`
if ! [[ -x $ASCIIDOCTOR_BIN ]]; then  ......

任何人都可以解释这是为什么吗?我被告知要避免使用双括号并且好奇,如果有其他方法可以使这个脚本工作。

我正在开发 Ubuntu 20.04。

标签: bash

解决方案


您的问题是您缺少引号,并且不了解参数扩展的工作原理:

假设您输入 bash 提示符,请考虑以下内容:

$ a=""
$ b="helloWorld"
$ bash -c 'for arg; do echo "got arg: $arg"; done' _ $a $b
got arg: helloWorld

您会假设使用位置参数调用 bash:

$0 = _
$1 = "" # empty string
$2 = "helloWorld"

但实际上,参数$a扩展为空,导致 bash 被调用:

$0 = _
$1 = "helloWorld"

将我们的知识应用于您的示例,您会注意到 if$ASCIIDOCTOR_BIN为空,即当命令不存在时,if 语句将变为:

if [ -x ]; then ...

它将测试字符串-x是否为空,显然不是。

解决方案是始终引用参数扩展:

$ a=""
$ b="helloWorld"
$ bash -c 'for arg; do echo "got arg: $arg"; done' _ "$a" "$b"
got arg: 
got arg: helloWorld

你应该知道的一件事[是它不是语言语法的一部分,而是一个命令,通常在 shell 中实现。

trueand也是如此false,这些也是命令,这意味着[ false ]只是测试字符串false是否为空,显然不是。

所以参数扩展等适用于它的所有参数。

上的注释[[[[是一种特殊的 bash 语法,其中参数扩展的工作方式不同,因此您的代码可以工作。

你可以找到一篇关于参数扩展如何在 bash 中工作的很好的文章:https ://mywiki.wooledge.org/BashGuide/Parameters


推荐阅读