Bash中的三元运算符(?:)


441

有没有办法做这样的事情

int a = (b == 5) ? c : d;

使用Bash?


1
@dutCh的答案表明bash确实具有与“三元运算符”相似的内容,但是在bash此称为“条件运算符” expr?expr:expr(请参阅man bashgoto节“算术评估”)。请记住,bash“条件运算符”非常棘手,并且有些陷阱。
Trevor Boyd Smith,

Bash确实具有整数的三元运算符,并且在算术表达式内部起作用((...))。请参阅Shell算术
codeforester

1
就像@codeforester提到的那样,三元运算符可用于算术扩展$(( ))和算术运算(( ))。另请参阅https://mywiki.wooledge.org/ArithmeticExpression

Answers:


489

三元运算符? :只是if/else

case "$b" in
 5) a=$c ;;
 *) a=$d ;;
esac

要么

 [[ $b = 5 ]] && a="$c" || a="$d"

103
请注意,=运算符将测试字符串是否相等,而不是数字相等(即,[[ 05 = 5 ]]是否为假)。如果要进行数值比较,请-eq改用。
戈登·戴维森

10
它是if/then/else
vol7ron

15
这是一种利用短路行为获得三元运算符效果的天才方法:) :) :)
mtk

6
为什么[[和]]?它的工作原理如下:[$ b = 5] && a =“ $ c” || a =“ $ d”
kdubs

83
cond && op1 || op2构造有一个固有的错误:如果op1由于某种原因而具有非零退出状态,则结果将静默变为op2if cond; then op1; else op2; fi也是一行,没有那个缺陷。
ivan_pozdeev

375

码:

a=$([ "$b" == 5 ] && echo "$c" || echo "$d")

58
这比其他方法要好。关于三元运算符的一点是它是一个运算符,因此它的正确上下文在表达式中,因此它必须返回一个值。
nic ferrier,2012年

2
这是最简洁的方法。请注意,如果with的部分echo "$c"是带别名的多行命令(例如echo 1; echo 2),则应将其括在括号中。
马特

2
这也将捕获已测试命令的任何输出(是的,在这种情况下,我们“知道”它不会产生任何输出)。
ivan_pozdeev

8
如果您确定后面的命令不会有非零的退出状态,则此操作符的行为仅类似于三元操作符&&。否则,如果成功但失败,a && b || c 将“意外”运行。cab
chepner

154

如果条件仅是检查是否设置了变量,则甚至有一个较短的形式:

a=${VAR:-20}

将分配给if 设置a的值,否则将为其分配默认值-这也可以是表达式的结果。VARVAR20

正如Alex在评论中指出的那样,该方法在技术上称为“参数扩展”。


6
在传递带有连字符的字符串参数的情况下,我必须使用引号: a=${1:-'my-hyphenated-text'}
saranicole '16

1
懒惰的链接 -除了替代(:-)之外,还有其他运算符
贾斯汀·沃伯

10
@JustinWrobel-不幸的是没有像这样的语法${VAR:-yes:-no}
肯·威廉姆斯

76
if [ "$b" -eq 5 ]; then a="$c"; else a="$d"; fi

cond && op1 || op2其他答案中建议的表达式存在一个固有错误:如果op1退出状态为非零,则op2默默地成为结果;错误也不会在-e模式下捕获。所以,这表达仅仅是安全的使用,如果op1不能失败(例如:true如果一个内置的,或者不能够失败(如部门和操作系统调用)的任何操作变量赋值)。

注意""引号。如果$b空白或空白,第一对将防止语法错误。其他将阻止将所有空格转换为单个空格。


1
我还看到了前缀,我相信[ "x$b" -eq "x" ]它专门用于测试空字符串。我喜欢使用zsh所使用的语法(zshexpn联机帮助页中的“ PARAMETER EXPANSION”),但是我对它们的可移植性并不了解。
约翰·P


46
(( a = b==5 ? c : d )) # string + numeric

31
这对数字比较和赋值很有用,但是如果将其用于字符串比较和赋值,它将产生无法预测的结果.... (( ))将任何/所有字符串都视为0
Peter.O 2011年

3
也可以这样写:a=$(( b==5 ? c : d ))
joeytwiddle

33
[ $b == 5 ] && { a=$c; true; } || a=$d

这样可以避免在||之后执行部分 &&和||之间的代码是偶然的 失败。


-e模式下,这仍然不会捕获错误:(set -o errexit; [ 5 == 5 ] && { false; true; echo "success"; } || echo "failure"; echo $?; echo "further on";)->success 0 further on
ivan_pozdeev '16

2
使用:bulit-in而不是true保存exec外部程序。
汤姆·黑尔

@ivan_pozdeev有什么方法可以使用&&.. ||并仍然在它们之间捕获失败的命令?
汤姆·黑尔

2
@TomHale编号&&||按照定义适用于它们之前的整个命令。因此,如果前面有两个命令(不管它们如何组合),则不能将其仅应用于其中一个,而不能应用于另一个。您可以模拟if/ then/ else用标志变量的逻辑,但何必如果有if/ then/ else合适?
ivan_pozdeev

14

命令支持基本算一个需要的最:

let a=b==5?c:d;

自然,这仅适用于分配变量。它无法执行其他命令。


24
它完全等效于((... ...)),因此仅对算术表达式有效
drAlberT 2013年

13

这是另一个选项,您只需指定一次要分配的变量,而分配的内容是字符串还是数字都没有关系:

VARIABLE=`[ test ] && echo VALUE_A || echo VALUE_B`

只是一个想法。:)


主要缺点:它还会捕获的标准配置[ test ]。因此,只有在您“知道”该命令不会向stdout输出任何内容时,该结构才可以安全使用。
ivan_pozdeev '18年

也与stackoverflow.com/questions/3953645/ternary-operator-in-bash/…相同,此外还需要在内部引用和转义引用。容忍空间的版本如下所示VARIABLE="`[ test ] && echo \"VALUE_A\" || echo \"VALUE_B\"`"
ivan_pozdeev '18

8

以下似乎适用于我的用例:

例子

$ tern 1 YES NO                                                                             
YES

$ tern 0 YES NO                                                                             
NO

$ tern 52 YES NO                                                                            
YES

$ tern 52 YES NO 52                                                                         
NO

并可以在如下脚本中使用:

RESULT=$(tern 1 YES NO)
echo "The result is $RESULT"

燕鸥

function show_help()
{
  echo ""
  echo "usage: BOOLEAN VALUE_IF_TRUE VALUE_IF_FALSE {FALSE_VALUE}"
  echo ""
  echo "e.g. "
  echo ""
  echo "tern 1 YES NO                            => YES"
  echo "tern 0 YES NO                            => NO"
  echo "tern "" YES NO                           => NO"
  echo "tern "ANY STRING THAT ISNT 1" YES NO     => NO"
  echo "ME=$(tern 0 YES NO)                      => ME contains NO"
  echo ""

  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$3" ]
then
  show_help
fi

# Set a default value for what is "false" -> 0
FALSE_VALUE=${4:-0}

function main
{
  if [ "$1" == "$FALSE_VALUE" ]; then
    echo $3
    exit;
  fi;

  echo $2
}

main "$1" "$2" "$3"

7
非常说明。很完整 很冗长。我喜欢三件事。;-)
杰西·奇斯霍尔姆

2
ternBash的一部分吗?Mac似乎没有它
极性

4
嘿@太极者无极而生-这是bash脚本的名称-将上面的“ tern”部分保存到名为“ tern”的文件中,然后chmod 700 tern在同一文件夹中运行。现在你将有一个tern在你的终端命令
布拉德·帕克斯

8

对于三元运算符,我们可以在Shell脚本中使用以下三种方式:

    [ $numVar == numVal ] && resVar="Yop" || resVar="Nop"

Or

    resVar=$([ $numVar == numVal ] && echo "Yop" || echo "Nop")

Or

    (( numVar == numVal ? (resVar=1) : (resVar=0) ))

实际上(这是这三个示例中的第一个和第二个),这是恕我直言这个问题的最合适答案。
netpoetica


5
(ping -c1 localhost&>/dev/null) && { echo "true"; } || {  echo "false"; }

4

如果您想要类似的语法,可以使用它

a=$(( $((b==5)) ? c : d ))

这仅适用于整数。您可以将其编写得更简单,因为a=$(((b==5) ? : c : d))- $((...))仅在我们要将算术结果分配给另一个变量时才需要。
codeforester

2

以下是一些选项:

1-如果在另一行中使用,则可以使用。

if [[ "$2" == "raiz" ]] || [[ "$2" == '.' ]]; then pasta=''; else pasta="$2"; fi

2-编写这样的函数:

 # Once upon a time, there was an 'iif' function in MS VB ...

function iif(){
  # Echoes $2 if 1,banana,true,etc and $3 if false,null,0,''
  case $1 in ''|false|FALSE|null|NULL|0) echo $3;;*) echo $2;;esac
}

这样使用内部脚本

result=`iif "$expr" 'yes' 'no'`

# or even interpolating:
result=`iif "$expr" "positive" "negative, because $1 is not true"` 

3-启发案例回答,一种更灵活的方法是:

 case "$expr" in ''|false|FALSE|null|NULL|0) echo "no...$expr";;*) echo "yep $expr";;esac

 # Expression can be something like:     
   expr=`expr "$var1" '>' "$var2"`

2

这是一个通用的解决方案

  • 也适用于字符串测试
  • 感觉像是一种表达
  • 当条件失败时避免任何细微的副作用

通过数值比较进行测试

a = $(if [ "$b" -eq 5 ]; then echo "$c"; else echo "$d"; fi)

用字符串比较测试

a = $(if [ "$b" = "5" ]; then echo "$c"; else echo "$d"; fi)


1

这很像弗拉基米尔的好答案。如果您的“三元”是“如果为true,则为字符串,如果为false,为空”的情况,则只需执行以下操作:

$ c="it was five"
$ b=3
$ a="$([[ $b -eq 5 ]] && echo "$c")"
$ echo $a

$ b=5
$ a="$([[ $b -eq 5 ]] && echo "$c")"
$ echo $a
it was five

1

回答: int a = (b == 5) ? c : d;

写就好了:

b=5
c=1
d=2
let a="(b==5)?c:d"

echo $a # 1

b=6;
c=1;
d=2;
let a="(b==5)?c:d"

echo $a # 2

请记住,“表达式”等效于$((expression))


0

面向字符串的替代方法,它使用数组:

spec=(IGNORE REPLACE)
for p in {13..15}; do
  echo "$p: ${spec[p==14]}";
done

输出:

13: IGNORE
14: REPLACE
15: IGNORE
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.