在Shell脚本表达式中,"plus colon"("+:")是什么意思?

23

这是什么意思?

if ${ac_cv_lib_lept_pixCreate+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS

看起来ac_cv_lib_lept_pixCreate是一个变量,那么+:代表什么?

在哪里学习完整的花括号表达式语法?这种语法的名称是什么?


那是一个冒号,不是逗号。 - Marcin
2
是一个所谓的 POSIX 特殊内置命令。 - Rahul Tripathi
2
阅读此处:https://dev59.com/unA75IYBdhLWcg3wkZ6A 和 http://wiki.bash-hackers.org/syntax/pe - Srini V
4个回答

30
在 “加号冒号” 表达式中,只有 + 在 shell 中具有特殊意义。 在这种情况下,冒号只是一个字符串值,因此我们可以将该片段编写为 ${...+":"}。 但是,因为它也是 shell 命令列表中的第一个单词,它成为了始终返回 true 的“命令”:
根据变量是否具有值的问题,if语句变成了if true false;if false;

让我们来分解一下:

为了方便起见,假设变量被称为var,并考虑表达式:

if ${var+:} false; then ...

如果 shell 变量 $var 存在,则整个表达式将被替换为 :;如果不存在,则返回一个空字符串。

因此,整个表达式 ${var+:} false 将变为 : false(返回 true),或者是 false(返回 false)。

这实际上是一种存在性测试,即使变量没有分配任何值也可以是 true。

尽管非常神秘,但事实上它是少数在大多数 Bourne 衍生 shell 中实际有效的变量存在性测试之一。

可能等价的表达式:(用任何变量名替换var

if [[ ${var+"is_set"} == is_set ]]; then ...

或者,可能更具可移植性:

case ${var+"IS_SET"} in IS_SET) ...;; esac

4
如果你想知道的话,autoconf这样做是因为:不是所有的shell都支持[[ ... ]]语法,旧的[ ... ]也被称为test ...机制在传统Unix系统上有大量变化,并且可能没有内置(会减慢速度),最后,方括号在autoconf代码中直接使用会很麻烦,因为它们被用于M4引号。 - zwol
@Zack - 很好的观点 - autoconf 需要考虑所有可能的 shell。我喜欢我的一些巧妙编码,但是尝试将特殊构造包装在函数中以隔离并解释其用途 - 对于这种情况来说行不通。 - Henk Langeveld
@Zack - 更新了有关神秘习语的部分。 - Henk Langeveld
实际上在大多数 Bourne 派生的 shell 中都可以工作。”所以,您是说它可以在 Bourne 派生的 shell 中工作? - Cloud
另一种变化形式:[ "${var+fnord}" ] 如果 var 已设置,则返回 true。 - tripleee
这很可能证明Bash的创造者曾经服用LSD,而LSD可能对人类大脑没有益处。 - Andy Ray

18

对于bash的Shell参数扩展文档,请点击此处。没有提及+:,但提到了:+:

${parameter:+word}
如果parameter为空或未设置,则不会替换为任何内容,否则将替换为word的展开结果。


1
前导冒号是可选的,因此${var+:}表示“如果$var被设置为任何值,则在此处替换冒号,否则不进行替换”。 - jthill
10
不完全是可选项,但可以省略以提供稍微不同的含义。${var:+:}会展开为:,如果var未设置或为空。${var+:}只有在var未设置时才会展开为:,而不是当它具有空值时。 - chepner
8
省略冒号的扩展运算符通常与“省略冒号只会测试未设置参数”的说明一起描述,这是在列出运算符列表之前提到的。 - chepner
2
@chepner 我认为你的意思是${var:+:}会在变量不为空或未设置时扩展为:;同样,${var+:}会在变量未设置时扩展为: - Henk Langeveld
1
@HenkLangeveld 可能吧。对于 ${var:-} 运算符,整个带/不带冒号的事情对我来说更有意义,当 ${var:+} 在某种意义上是反向运算符时,我会感到困惑。 - chepner

10

为了说明已经说过的内容:

未设置的变量(请注意某些echo命令的结果是空行):

$ unset foo
$ echo ${foo}

$ echo ${foo:+:}

$ echo ${foo+:}

Null变量:

$ foo=""
$ echo ${foo}

$ echo ${foo:+:}

$ echo ${foo+:}
:

非空变量:

$ foo="bar"
$ echo ${foo}
bar
$ echo ${foo:+:}
:
$ echo ${foo+:}
:

3

简单的例子可以证明

我检查参数TEST是否存在,如果存在则输出"Yes",否则输出"No"

openvas:~$ ${TEST+:} false  &&  echo "yes" || echo "no"
no
openvas:~$ TEST=1
openvas:~$ ${TEST+:} false  &&  echo "yes" || echo "no"
yes
openvas:~$ 

如果您看到,参数TEST已被评估,实际上未设置,因此返回false并退出路径,并转到OR。一旦我设置相同的内容并再次测试,它将流动到echo部分(继续&&),因为它返回true。
参考:这个那个

1
从技术上讲,第一个“TEST”未设置,而不是空。 - chepner
不是一个合适的例子。${TEST} false && echo "yes" || echo "no"也会打印出no。因此,这并没有准确定位 +: 加入到混合中所起的作用。 - ychaouche

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接