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

发布于 2024-09-28 00:46:44 字数 89 浏览 8 评论 0原文

有没有办法

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

使用 Bash 来做这样的事情?

Is there a way to do something like this

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

using Bash?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(23

孤独陪着我 2024-10-05 00:46:44

三元运算符 ? : 只是 if/then/else 的缩写形式

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

或者

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

ternary operator ? : is just a short form of if/then/else

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

Or

 [[ $b = 5 ]] && a="$c" || a="$d"
烂人 2024-10-05 00:46:44

代码:

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

Code:

a=$([ "$b" == 5 ] && echo "$c" || echo "$d")
指尖微凉心微凉 2024-10-05 00:46:44

如果条件只是检查变量是否已设置,则还有更简短的形式:

a=${VAR:-20}

如果 VAR 为,则将 VAR 的值分配给 a设置,否则它将为其分配默认值20——这也可以是表达式的结果。

这种方法在技术上称为“参数扩展”。

If the condition is merely checking if a variable is set, there's even a shorter form:

a=${VAR:-20}

will assign to a the value of VAR if VAR is set, otherwise it will assign it the default value 20 -- this can also be a result of an expression.

This approach is technically called "Parameter Expansion".

枯寂 2024-10-05 00:46:44
if [[ $b -eq 5 ]]; then a="$c"; else a="$d"; fi

cond &&操作1 ||其他答案中建议的 op2 表达式有一个固有的错误:如果 op1 具有非零退出状态,则 op2 默默地成为结果;在 -e 模式下也不会捕获该错误。因此,只有当 op1 永远不会失败时,该表达式才可以安全使用(例如,:, true 如果是内置函数,或者没有任何变量赋值可能失败的操作(例如除法和操作系统调用))。

请注意 "" 引号。它们将阻止将所有空白转换为单个空格。

如果 $b 等于 test 运算符(例如“-z”),则双方括号(而不是单方括号)可防止错误操作(例如“-z”;解决方法与 [[ "x$b" == "xyes" ] 并且它仅适用于字符串比较);他们还提高了报价要求。

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

The cond && op1 || op2 expression suggested in other answers has an inherent bug: if op1 has a nonzero exit status, op2 silently becomes the result; the error will also not be caught in -e mode. So, that expression is only safe to use if op1 can never fail (e.g., :, true if a builtin, or variable assignment without any operations that can fail (like division and OS calls)).

Note the "" quotes. They will prevent translation of all whitespace into single spaces.

Double square brackets as opposed to single ones prevent incorrect operation if $b is equal to a test operator (e.g. "-z"; a workaround with [ is [ "x$b" == "xyes" ] and it only works for string comparison); they also lift the requirement for quoting.

转角预定愛 2024-10-05 00:46:44
(( a = b==5 ? c : d )) # string + numeric
(( a = b==5 ? c : d )) # string + numeric
回首观望 2024-10-05 00:46:44
[ $b == 5 ] && { a=$c; true; } || a=$d

这将避免执行 || 之后的部分意外地当 && 之间的代码和 ||失败了。

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

This will avoid executing the part after || by accident when the code between && and || fails.

給妳壹絲溫柔 2024-10-05 00:46:44

我们可以在 Shell 脚本中使用以下三种方法来实现三元运算符:

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

Or

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

Or

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

更新: 使用下面的可立即运行的示例扩展字符串计算的答案。这是利用上面提到的第二种格式。

$ strVar='abc';resVar=$([[ $strVar == 'abc' ]] && echo "Yop" || echo "Nop");echo $resVar
Yop
$ strVar='aaa';resVar=$([[ $strVar == 'abc' ]] && echo "Yop" || echo "Nop");echo $resVar
Nop

We can use following three ways in Shell Scripting for ternary operator :

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

Or

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

Or

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

Update: Extending the answer for string computations with below ready-to-run example. This is making use of second format mentioned above.

$ strVar='abc';resVar=$([[ $strVar == 'abc' ]] && echo "Yop" || echo "Nop");echo $resVar
Yop
$ strVar='aaa';resVar=$([[ $strVar == 'abc' ]] && echo "Yop" || echo "Nop");echo $resVar
Nop
自由如风 2024-10-05 00:46:44

let 命令支持大多数需要的基本运算符:

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

当然,这仅适用于分配变量;它不能执行其他命令。

The let command supports most of the basic operators one would need:

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

Naturally, this works only for assigning variables; it cannot execute other commands.

趁微风不噪 2024-10-05 00:46:44

这是另一个选项,您只需指定要分配的变量一次,并且分配的是字符串还是数字并不重要:

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

只是一个想法。 :)

Here is another option where you only have to specify the variable you're assigning once, and it doesn't matter whether what your assigning is a string or a number:

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

Just a thought. :)

月亮是我掰弯的 2024-10-05 00:46:44

bash 中的三元条件也有一个非常相似但更简单的语法:

a=$(( b == 5 ? 123 : 321  ))

There's also a very similar but simpler syntax for ternary conditionals in bash:

a=$(( b == 5 ? 123 : 321  ))
稚气少女 2024-10-05 00:46:44

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

示例

$ 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"

tern

#!/usr/bin/env bash

function show_help()
{
  ME=$(basename "$0")
  IT=$(cat <<EOF

  Returns a ternary result

  usage: BOOLEAN VALUE_IF_TRUE VALUE_IF_FALSE
  
  e.g. 
  
  # YES
  $ME 1 YES NO                                

  # NO
  $ME 0 YES NO

  # NO
  $ME "" YES NO

  # YES
  $ME "STRING THAT ISNT BLANK OR 0" YES NO

  # INFO contains NO
  INFO=\$($ME 0 YES NO)
EOF
)
  echo "$IT"
  echo
  exit
}

if [ "$1" = "help" ] || [ "$1" = '?' ] || [ "$1" = "--help" ] || [ "$1" = "h" ]; 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" ] || [ "$1" = '' ]; then
    echo $3
    exit;
  fi;

  echo $2
}

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

The following seems to work for my use cases:

Examples

$ tern 1 YES NO                                                                             
YES
    
$ tern 0 YES NO                                                                             
NO
    
$ tern 52 YES NO                                                                            
YES
    
$ tern 52 YES NO 52                                                                         
NO

and can be used in a script like so:

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

tern

#!/usr/bin/env bash

function show_help()
{
  ME=$(basename "$0")
  IT=$(cat <<EOF

  Returns a ternary result

  usage: BOOLEAN VALUE_IF_TRUE VALUE_IF_FALSE
  
  e.g. 
  
  # YES
  $ME 1 YES NO                                

  # NO
  $ME 0 YES NO

  # NO
  $ME "" YES NO

  # YES
  $ME "STRING THAT ISNT BLANK OR 0" YES NO

  # INFO contains NO
  INFO=\$($ME 0 YES NO)
EOF
)
  echo "$IT"
  echo
  exit
}

if [ "$1" = "help" ] || [ "$1" = '?' ] || [ "$1" = "--help" ] || [ "$1" = "h" ]; 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" ] || [ "$1" = '' ]; then
    echo $3
    exit;
  fi;

  echo $2
}

main "$1" "$2" "$3"
Saygoodbye 2024-10-05 00:46:44

这是一个通用的解决方案,它

  • 也适用于字符串测试,
  • 感觉就像一个表达式
  • ,当条件失败时避免任何微妙的副作用

使用数字比较进行测试

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

使用字符串比较进行测试

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

Here's a general solution, that

  • works with string tests as well
  • feels rather like an expression
  • avoids any subtle side effects when the condition fails

Test with numerical comparison

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

Test with String comparison

a=$(if [ "$b" = "5" ]; then echo "$c"; else echo "$d"; fi)
望喜 2024-10-05 00:46:44
(ping -c1 localhost&>/dev/null) && { echo "true"; } || {  echo "false"; }
(ping -c1 localhost&>/dev/null) && { echo "true"; } || {  echo "false"; }
凉城 2024-10-05 00:46:44

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

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

You can use this if you want similar syntax

a=$(( $((b==5)) ? c : d ))
吾家有女初长成 2024-10-05 00:46:44

有些人已经提出了一些不错的替代方案。我想让语法尽可能接近,所以我编写了一个名为 ? 的函数。

这允许语法:

[[ $x -eq 1 ]]; ? ./script1 : ./script2
# or
? '[[ $x -eq 1 ]]' ./script1 : ./script2

在这两种情况下,: 是可选的。所有包含空格的参数、值都必须用引号引起来,因为它使用 eval 运行它们。

如果 子句不是命令,则函数 echo 是正确的值。

./script; ? Success! : "Failure :("

功能

?() {
  local lastRet=$?
  if [[ $1 == --help || $1 == -? ]]; then
    echo 

显然如果你想让脚本更短,你可以删除帮助文本。

编辑:我不知道充当文件名中的占位符。它不像 * 那样匹配任意数量的字符,而是精确匹配一个字符。因此,如果您的工作目录中有一个单字符文件,bash 将尝试将该文件名作为命令运行。我不知道如何解决这个问题。我想使用命令“?” ...args 可能有效,但是没有骰子。

\e[37;1mUsage:\e[0m ? [<condition>] <then> [:] <else> If \e[37;1m<then>\e[0m and/or \e[37;1m<else>\e[0m are not valid commands, then their values are printed to stdOut, otherwise they are executed. If \e[37;1m<condition>\e[0m is not specified, evaluates the return code ($?) of the previous statement. \e[37;1mExamples:\e[0m myVar=$(? "[[ $x -eq 1 ]] foo bar) \e[32;2m# myVar is set to "foo" if x is 1, else it is set to "bar"\e[0m ? "[[ $x = *foo* ]] "cat hello.txt" : "cat goodbye.txt" \e[32;2m# runs cat on "hello.txt" if x contains the word "foo", else runs cat on # "goodbye.txt"\e[0m ? "[[ $x -eq 1 ]] "./script1" "./script2"; ? "Succeeded!" "Failed :(" \e[32;2m# If x = 1, runs script1, else script2. If the run script succeeds, prints # "Succeeded!", else prints "failed".\e[0m' return elif ! [[ $# -eq 2 || $# -eq 3 || $# -eq 4 && $3 == ':' ]]; then 1>&2 echo

显然如果你想让脚本更短,你可以删除帮助文本。

编辑:我不知道充当文件名中的占位符。它不像 * 那样匹配任意数量的字符,而是精确匹配一个字符。因此,如果您的工作目录中有一个单字符文件,bash 将尝试将该文件名作为命令运行。我不知道如何解决这个问题。我想使用命令“?” ...args 可能有效,但是没有骰子。

\e[37;1m?\e[0m requires 2 to 4 arguments \e[37;1mUsage\e[0m: ? [<condition>] <then> [:] <else> Run \e[37;1m? --help\e[0m for more details' return 1 fi local cmd if [[ $# -eq 2 || $# -eq 3 && $2 == ':' ]]; then cmd="[[ $lastRet -eq 0 ]]" else cmd="$1" shift fi if [[ $2 == ':' ]]; then eval "set -- '$1' '$3'" fi local result=$(eval "$cmd" && echo "$1" || echo "$2") if command -v ${result[0]} &> /dev/null; then eval "${result[@]}" else echo "${result[@]}" fi }

显然如果你想让脚本更短,你可以删除帮助文本。

编辑:我不知道充当文件名中的占位符。它不像 * 那样匹配任意数量的字符,而是精确匹配一个字符。因此,如果您的工作目录中有一个单字符文件,bash 将尝试将该文件名作为命令运行。我不知道如何解决这个问题。我想使用命令“?” ...args 可能有效,但是没有骰子。

Some people have already presented some nice alternatives. I wanted to get the syntax as close as possible, so I wrote a function named ?.

This allows for the syntax:

[[ $x -eq 1 ]]; ? ./script1 : ./script2
# or
? '[[ $x -eq 1 ]]' ./script1 : ./script2

In both cases, the : is optional. All arguments that have spaces, the values must be quoted since it runs them with eval.

If the <then> or <else> clauses aren't commands, the function echos the proper value.

./script; ? Success! : "Failure :("

The function

?() {
  local lastRet=$?
  if [[ $1 == --help || $1 == -? ]]; then
    echo 

Obviously if you want the script to be shorter, you can remove the help text.

EDIT: I was unaware that ? acts as a placeholder character in a file name. Rather than matching any number of characters like *, it matches exactly one character. So, if you have a one-character file in your working directory, bash will try to run the filename as a command. I'm not sure how to get around this. I thought using command "?" ...args might work but, no dice.

\e[37;1mUsage:\e[0m ? [<condition>] <then> [:] <else> If \e[37;1m<then>\e[0m and/or \e[37;1m<else>\e[0m are not valid commands, then their values are printed to stdOut, otherwise they are executed. If \e[37;1m<condition>\e[0m is not specified, evaluates the return code ($?) of the previous statement. \e[37;1mExamples:\e[0m myVar=$(? "[[ $x -eq 1 ]] foo bar) \e[32;2m# myVar is set to "foo" if x is 1, else it is set to "bar"\e[0m ? "[[ $x = *foo* ]] "cat hello.txt" : "cat goodbye.txt" \e[32;2m# runs cat on "hello.txt" if x contains the word "foo", else runs cat on # "goodbye.txt"\e[0m ? "[[ $x -eq 1 ]] "./script1" "./script2"; ? "Succeeded!" "Failed :(" \e[32;2m# If x = 1, runs script1, else script2. If the run script succeeds, prints # "Succeeded!", else prints "failed".\e[0m' return elif ! [[ $# -eq 2 || $# -eq 3 || $# -eq 4 && $3 == ':' ]]; then 1>&2 echo

Obviously if you want the script to be shorter, you can remove the help text.

EDIT: I was unaware that ? acts as a placeholder character in a file name. Rather than matching any number of characters like *, it matches exactly one character. So, if you have a one-character file in your working directory, bash will try to run the filename as a command. I'm not sure how to get around this. I thought using command "?" ...args might work but, no dice.

\e[37;1m?\e[0m requires 2 to 4 arguments \e[37;1mUsage\e[0m: ? [<condition>] <then> [:] <else> Run \e[37;1m? --help\e[0m for more details' return 1 fi local cmd if [[ $# -eq 2 || $# -eq 3 && $2 == ':' ]]; then cmd="[[ $lastRet -eq 0 ]]" else cmd="$1" shift fi if [[ $2 == ':' ]]; then eval "set -- '$1' '$3'" fi local result=$(eval "$cmd" && echo "$1" || echo "$2") if command -v ${result[0]} &> /dev/null; then eval "${result[@]}" else echo "${result[@]}" fi }

Obviously if you want the script to be shorter, you can remove the help text.

EDIT: I was unaware that ? acts as a placeholder character in a file name. Rather than matching any number of characters like *, it matches exactly one character. So, if you have a one-character file in your working directory, bash will try to run the filename as a command. I'm not sure how to get around this. I thought using command "?" ...args might work but, no dice.

梨涡少年 2024-10-05 00:46:44

最简单的三元

brew list | grep -q bat && echo 'yes' || echo 'no'

这个示例将确定您是否使用 homebrew 安装 bat

如果为 true,您将看到“yes”

如果为 false,您将看到“no”

我添加了-q 抑制此处的 grepped 字符串输出,因此您只能看到“yes”或“

doSomethingAndCheckTruth && echo 'yes' || echo 'no'

no /code> 和 zsh

Simplest ternary

brew list | grep -q bat && echo 'yes' || echo 'no'

This example will determine if you used homebrew to install bat or not yet

If true you will see "yes"

If false you will see "no"

I added the -q to suppress the grepped string output here, so you only see "yes" or "no"

Really the pattern you seek is this

doSomethingAndCheckTruth && echo 'yes' || echo 'no'

Tested with bash and zsh

旧瑾黎汐 2024-10-05 00:46:44

以下是一些选项:

1- 在一行中使用 if then else 是可能的。

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"`

Here are some options:

1- Use if then else in one line, it is possible.

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

2- Write a function like this:

 # 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
}

use inside script like this

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

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

3- Inspired in the case answer, a more flexible and one line use is:

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

 # Expression can be something like:     
   expr=`expr "$var1" '>' "$var2"`
抚你发端 2024-10-05 00:46:44

回答: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

记住“表达式”相当于$((表达式))

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

just write:

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

remember that " expression " is equivalent to $(( expression ))

无风消散 2024-10-05 00:46:44

另外两个答案

下面是一些思考

bash 整数变量

的方法除了 dutChVladimirghostdog74 的正确答案,因为这个问题是关于整数标记

有没有办法做这样的事情

int a = (b == 5) ?光盘;

有一种在bash下处理整数的好方法:

declare -i b=' RANDOM % 3 + 4 ' c=100 d=50 a='  b == 5 ? c : d '; echo $b '-->' $a

该命令的输出行应该是以下之一:

4 --> 50
5 --> 100
6 --> 50

当然,声明变量的整数类型是完成一次:

declare -i a b c d
c=100 d=50 b=RANDOM%3+4
a=' b == 5 ? c : d '
echo $a $b
100 5
b=12 a=b==5?c:d
echo $a $b
50 12

注意:推荐使用此语法。声明变量的属性,然后赋值,最好单独完成。

题外话:使用字符串作为数学函数

mathString=' b == 5 ? c : d '
b=5 a=$mathString
echo $a $b
100 5

b=1 a=$mathString 
echo $a $b
50 1

基于参数扩展间接

以下答案来自Brad Parksdruid62,这是一种方法不限于整数

c=50 d=100 ar=([5]=c)
read -p 'Enter B: ' b
e=${ar[b]:-d};echo ${!e}
  • 如果b==5,则ar[b]c并且间接 do c50
  • 否则,ar[除 5 之外的任何值] 为空,因此参数扩展将默认为d,其中间接100

使用数组而不是整数的相同演示

ternArrayDemo(){
    local -a c d e ar
    local b
    c=(foo bar) d=(foo bar baz) e=(empty) ar=([5]=c [2]=d)
    b=${ar[$1]:-e}
    b+=[@]      # For array indirection
    printf ' - %s\n' "${!b}"
}

然后

ternArrayDemo 0
 - empty
ternArrayDemo 2 
 - foo
 - bar
 - baz
ternArrayDemo 4
 - empty
ternArrayDemo 5
 - foo
 - bar
ternArrayDemo 6
 - empty

或使用关联数组

ternAssocArrayDemo(){
     local -a c d e
     local -A ar
     local b
     c=(foo bar) d=(foo bar baz) e=(empty)
     ar=([foo]=c[@] [bar]=d[@] [baz]=d[-1])
     b=${ar[$1]:-e[@]}
     printf ' - %s\n' "${!b}"
}

然后

ternAssocArrayDemo hello
 - empty
ternAssocArrayDemo foo
 - foo
 - bar
ternAssocArrayDemo bar
 - foo
 - bar
 - baz
ternAssocArrayDemo baz
 - baz

Two more answers

Here's some ways of thinking about this

bash integer variables

In addition to, dutCh, Vladimir and ghostdog74's corrects answers and because this question is regarding integer and tagged :

Is there a way to do something like this

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

There is a nice and proper way to work with integers under bash:

declare -i b=' RANDOM % 3 + 4 ' c=100 d=50 a='  b == 5 ? c : d '; echo $b '-->' $a

The output line from this command should by one of:

4 --> 50
5 --> 100
6 --> 50

Of course, declaring integer type of variable is to be done once:

declare -i a b c d
c=100 d=50 b=RANDOM%3+4
a=' b == 5 ? c : d '
echo $a $b
100 5
b=12 a=b==5?c:d
echo $a $b
50 12

Note: This syntax is recommanded. Declaring property of a variable, then assigning a value is better to be done separately.

Digression: Using a string as a math function:

mathString=' b == 5 ? c : d '
b=5 a=$mathString
echo $a $b
100 5

b=1 a=$mathString 
echo $a $b
50 1

Based on parameter expansion and indirection

Following answers from Brad Parks and druid62, here is a way not limited to integer:

c=50 d=100 ar=([5]=c)
read -p 'Enter B: ' b
e=${ar[b]:-d};echo ${!e}
  • If b==5, then ar[b] is c and indirection do c is 50.
  • Else ar[any value other than 5] is empty, so parameter expansion will default to d, where indirection give 100.

Same demo using an array instead of an integer

ternArrayDemo(){
    local -a c d e ar
    local b
    c=(foo bar) d=(foo bar baz) e=(empty) ar=([5]=c [2]=d)
    b=${ar[$1]:-e}
    b+=[@]      # For array indirection
    printf ' - %s\n' "${!b}"
}

Then

ternArrayDemo 0
 - empty
ternArrayDemo 2 
 - foo
 - bar
 - baz
ternArrayDemo 4
 - empty
ternArrayDemo 5
 - foo
 - bar
ternArrayDemo 6
 - empty

Or using associative arrays

ternAssocArrayDemo(){
     local -a c d e
     local -A ar
     local b
     c=(foo bar) d=(foo bar baz) e=(empty)
     ar=([foo]=c[@] [bar]=d[@] [baz]=d[-1])
     b=${ar[$1]:-e[@]}
     printf ' - %s\n' "${!b}"
}

Then

ternAssocArrayDemo hello
 - empty
ternAssocArrayDemo foo
 - foo
 - bar
ternAssocArrayDemo bar
 - foo
 - bar
 - baz
ternAssocArrayDemo baz
 - baz
最丧也最甜 2024-10-05 00:46:44

这很像弗拉基米尔的好答案。如果您的“三元”是“如果 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

This is much like Vladimir's fine answer. If your "ternary" is a case of "if true, string, if false, empty", then you can simply do:

$ 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
ま柒月 2024-10-05 00:46:44

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

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

输出:

13: IGNORE
14: REPLACE
15: IGNORE

A string-oriented alternative, that uses an array:

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

which outputs:

13: IGNORE
14: REPLACE
15: IGNORE
如果没有 2024-10-05 00:46:44

这种方法怎么样:

# any your function
function check () {
    echo 'checking...';

    # Change the following to 'true' to emulate a successful execution.
    # Note: You can replace check function with any function you wish.
    # Be aware in linux false and true are funcitons themselves. see 'help false' for instance.
    false; 
}

# double check pattern
check && echo 'update' \
    || check || echo 'create'; 

了解条件语句在 RxJ(即过滤器管道)中如何工作。
是的,这是代码重复,但从我的角度来看,这是更实用的方法。

What about such approach:

# any your function
function check () {
    echo 'checking...';

    # Change the following to 'true' to emulate a successful execution.
    # Note: You can replace check function with any function you wish.
    # Be aware in linux false and true are funcitons themselves. see 'help false' for instance.
    false; 
}

# double check pattern
check && echo 'update' \
    || check || echo 'create'; 

See how conditional statements works in the RxJs (i.e. filter pipe).
Yes, it is code duplication but more functional approach from my point of view.

画离情绘悲伤 2024-10-05 00:46:44

最上面的答案 [[ $b = 5 ]] && a="$c" ||仅当您确定 && 之后不会出现错误时才应使用 a="$d",否则它将错误地执行 | 之后的部分。 |。

为了解决这个问题,我编写了一个三元函数,它的行为应该如此,它甚至使用 ?: 运算符:

编辑 - 新解决方案

这里是我的新解决方案,不使用 $IFS 也不使用 ev(a/i)l

function executeCmds()
{
    declare s s1 s2 i j k
    declare -A cmdParts
    declare pIFS=$IFS
    IFS=

executeCmds 单独分隔每个命令,除了由于 &&|| 运算符而应跳过的命令之外。每当命令以 ! 或标志开头时,它就会使用 []

有两种方法可以向其传递命令:

  1. 传递不带引号的单个命令,但一定要引用 ;&&|| 运营商。
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
  1. 传递所有引用的命令:
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'

NB我发现无法将 &&|| 运算符作为不带引号的参数传递,因为它们是函数名称和别名中存在非法字符,而且我找不到覆盖 bash 运算符的方法。

旧解决方案 - 使用 ev(a/i)l

function t()
{
    pIFS=$IFS
    IFS="?"
    read condition success <<< "$@"
    IFS=":"
    read success failure <<< "$success"
    IFS=$pIFS
    eval "$condition" || { eval "$failure" ; return; }
    eval "$success"
}
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'
\n' declare results=($(echo "$1" | grep -oP '{ .*? }')) IFS=$pIFS s="$1" for ((i=0; i < ${#results[@]}; i++)); do s="${s/${results[$i]}/'\0'}" results[$i]="${results[$i]:2:${#results[$i]}-3}" results[$i]=$(echo ${results[$i]%%";"*}) done s="$s&&" let cmdParts[t]=0 while :; do i=${cmdParts[t]} let cmdParts[$i,t]=0 s1="${s%%"&&"*}||" while :; do j=${cmdParts[$i,t]} let cmdParts[$i,$j,t]=0 s2="${s1%%"||"*};" while :; do cmdParts[$i,$j,${cmdParts[$i,$j,t]}]=$(echo ${s2%%";"*}) s2=${s2#*";"} let cmdParts[$i,$j,t]++ [[ $s2 ]] && continue break done s1=${s1#*"||"} let cmdParts[$i,t]++ [[ $s1 ]] && continue break done let cmdParts[t]++ s=${s#*"&&"} [[ $s ]] && continue break done declare lastError=0 declare skipNext=false for ((i=0; i < ${cmdParts[t]}; i++ )) ; do let j=0 while :; do let k=0 while :; do if $skipNext; then skipNext=false else if [[ "${cmdParts[$i,$j,$k]}" == "\0" ]]; then executeCmds "${results[0]}" && lastError=0 || lastError=1 results=("${results[@]:1}") elif [[ "${cmdParts[$i,$j,$k]:0:1}" == "!" || "${cmdParts[$i,$j,$k]:0:1}" == "-" ]]; then [ ${cmdParts[$i,$j,$k]} ] && lastError=0 || lastError=1 else ${cmdParts[$i,$j,$k]} lastError=$? fi if (( k+1 < cmdParts[$i,$j,t] )); then skipNext=false elif (( j+1 < cmdParts[$i,t] )); then (( lastError==0 )) && skipNext=true || skipNext=false elif (( i+1 < cmdParts[t] )); then (( lastError==0 )) && skipNext=false || skipNext=true fi fi let k++ [[ $k<${cmdParts[$i,$j,t]} ]] || break done let j++ [[ $j<${cmdParts[$i,t]} ]] || break done done return $lastError } function t() { declare commands="$@" find="$(echo ?)" replace='?' commands="${commands/$find/$replace}" readarray -d '?' -t statement <<< "$commands" condition=${statement[0]} readarray -d ':' -t statement <<< "${statement[1]}" success="${statement[0]}" failure="${statement[1]}" executeCmds "$condition" || { executeCmds "$failure"; return; } executeCmds "$success" }

executeCmds 单独分隔每个命令,除了由于 &&|| 运算符而应跳过的命令之外。每当命令以 ! 或标志开头时,它就会使用 []

有两种方法可以向其传递命令:

  1. 传递不带引号的单个命令,但一定要引用 ;&&|| 运营商。
  1. 传递所有引用的命令:

NB我发现无法将 &&|| 运算符作为不带引号的参数传递,因为它们是函数名称和别名中存在非法字符,而且我找不到覆盖 bash 运算符的方法。

旧解决方案 - 使用 ev(a/i)l

The top answer [[ $b = 5 ]] && a="$c" || a="$d" should only be used if you are certain there will be no error after the &&, otherwise it will incorrectly excute the part after the ||.

To solve that problem I wrote a ternary function that behaves as it should and it even uses the ? and : operators:

Edit - new solution

Here is my new solution that does not use $IFS nor ev(a/i)l.

function executeCmds()
{
    declare s s1 s2 i j k
    declare -A cmdParts
    declare pIFS=$IFS
    IFS=

executeCmds separates each command individually, apart from the ones that should be skipped due to the && and || operators. It uses [] whenever a command starts with ! or a flag.

There are two ways to pass commands to it:

  1. Pass the individual commands unquoted but be sure to quote ;, &&, and || operators.
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
  1. Pass all the commands quoted:
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'

NB I found no way to pass in && and || operators as parameters unquoted, as they are illegal characters for function names and aliases, and I found no way to override bash operators.

Old solution - uses ev(a/i)l

function t()
{
    pIFS=$IFS
    IFS="?"
    read condition success <<< "$@"
    IFS=":"
    read success failure <<< "$success"
    IFS=$pIFS
    eval "$condition" || { eval "$failure" ; return; }
    eval "$success"
}
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'
\n' declare results=($(echo "$1" | grep -oP '{ .*? }')) IFS=$pIFS s="$1" for ((i=0; i < ${#results[@]}; i++)); do s="${s/${results[$i]}/'\0'}" results[$i]="${results[$i]:2:${#results[$i]}-3}" results[$i]=$(echo ${results[$i]%%";"*}) done s="$s&&" let cmdParts[t]=0 while :; do i=${cmdParts[t]} let cmdParts[$i,t]=0 s1="${s%%"&&"*}||" while :; do j=${cmdParts[$i,t]} let cmdParts[$i,$j,t]=0 s2="${s1%%"||"*};" while :; do cmdParts[$i,$j,${cmdParts[$i,$j,t]}]=$(echo ${s2%%";"*}) s2=${s2#*";"} let cmdParts[$i,$j,t]++ [[ $s2 ]] && continue break done s1=${s1#*"||"} let cmdParts[$i,t]++ [[ $s1 ]] && continue break done let cmdParts[t]++ s=${s#*"&&"} [[ $s ]] && continue break done declare lastError=0 declare skipNext=false for ((i=0; i < ${cmdParts[t]}; i++ )) ; do let j=0 while :; do let k=0 while :; do if $skipNext; then skipNext=false else if [[ "${cmdParts[$i,$j,$k]}" == "\0" ]]; then executeCmds "${results[0]}" && lastError=0 || lastError=1 results=("${results[@]:1}") elif [[ "${cmdParts[$i,$j,$k]:0:1}" == "!" || "${cmdParts[$i,$j,$k]:0:1}" == "-" ]]; then [ ${cmdParts[$i,$j,$k]} ] && lastError=0 || lastError=1 else ${cmdParts[$i,$j,$k]} lastError=$? fi if (( k+1 < cmdParts[$i,$j,t] )); then skipNext=false elif (( j+1 < cmdParts[$i,t] )); then (( lastError==0 )) && skipNext=true || skipNext=false elif (( i+1 < cmdParts[t] )); then (( lastError==0 )) && skipNext=false || skipNext=true fi fi let k++ [[ $k<${cmdParts[$i,$j,t]} ]] || break done let j++ [[ $j<${cmdParts[$i,t]} ]] || break done done return $lastError } function t() { declare commands="$@" find="$(echo ?)" replace='?' commands="${commands/$find/$replace}" readarray -d '?' -t statement <<< "$commands" condition=${statement[0]} readarray -d ':' -t statement <<< "${statement[1]}" success="${statement[0]}" failure="${statement[1]}" executeCmds "$condition" || { executeCmds "$failure"; return; } executeCmds "$success" }

executeCmds separates each command individually, apart from the ones that should be skipped due to the && and || operators. It uses [] whenever a command starts with ! or a flag.

There are two ways to pass commands to it:

  1. Pass the individual commands unquoted but be sure to quote ;, &&, and || operators.
  1. Pass all the commands quoted:

NB I found no way to pass in && and || operators as parameters unquoted, as they are illegal characters for function names and aliases, and I found no way to override bash operators.

Old solution - uses ev(a/i)l

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文