Bashの三項演算子(?:)


441

このようなことをする方法はありますか

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

Bashを使用していますか?


1
@dutChの答えbash、「3項演算子」に似たものがあることを示していますが、bashこれは「条件演算子」と呼ばれていますexpr?expr:exprman bash「算術評価」セクションを参照してください)。覚えておいてbash「条件演算子」はトリッキーであり、いくつかの落とし穴があります。
Trevor Boyd Smith

Bashには整数の三項演算子があり、算術式の内部で機能します((...))Shell Arithmeticを参照してください。
codeforester 2018

1
@codeforesterが述べたように、三項演算子は算術展開$(( ))と算術評価で機能し(( ))ます。もご覧くださいhttps://mywiki.wooledge.org/ArithmeticExpression
カイ

回答:


489

三項演算子? :は、if/else

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

または

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

103
=演算子は、数値の等価性ではなく文字列の等価性をテストすることに注意してください(つまり[[ 05 = 5 ]]、false)。数値比較が必要な場合は、-eq代わりに使用してください。
Gordon Davisson、

10
より短い形式ですif/then/else
vol7ron 2013

15
これは、短絡動作を利用して三項演算子効果を得る天才的な方法です:) :) :)
mtk

6
なぜ[[と]]?次のように機能します:[$ b = 5] && a = "$ c" || a = "$ d"
kdubs 2014年

83
cond && op1 || op2構築物は、固有のバグがあります場合はop1、何らかの理由でゼロ以外の終了ステータスがあり、その結果は黙っになりますop2if cond; then op1; else op2; fi1行でもあり、その欠陥はありません。
ivan_pozdeev 2017

375

コード:

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

58
これは他のものよりも優れています...三次演算子のポイントは、それが演算子であることです。したがって、適切なコンテキストは式内にあるため、値を返す必要があります。
nicフェリア2012年

2
これが最も簡潔な方法です。の部分echo "$c"がエイリアス化された複数行のコマンド(などecho 1; echo 2)である場合は、括弧で囲む必要があることに注意してください。
Matt

2
これは、テストされたコマンドの出力もキャプチャします(そうです、この特定のケースでは、何も生成しないことを "知っています")。
ivan_pozdeev

8
この演算子のチェーンは、後のコマンド&&がゼロ以外の終了ステータスにならないことが確実である場合にのみ、3項演算子のように動作します。それ以外の場合は、a && b || c 「予想外に」実行するc場合はa成功したがb失敗しました。
chepner

155

条件が変数が設定されているかどうかを確認するだけの場合は、さらに短い形式があります。

a=${VAR:-20}

if が設定されている場合はa値が割り当てられ、それ以外のVAR場合VARはデフォルト値が割り当てられます。20これは式の結果である場合もあります。

コメントでアレックスが指摘するように、このアプローチは技術的に「パラメータ拡張」と呼ばれています。


6
ハイフンが含まれる文字列パラメータを渡す場合、引用符を使用する必要がありました a=${1:-'my-hyphenated-text'}
。– saranicole

1
怠惰な人へのリンク -代わりの演算子があります(:-
Justin Wrobel

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分裂とOSコール)のように(失敗する可能性があります任意の操作をせずに組み込み、または変数割り当てている場合)。

""引用符に注意してください。最初のペア$bは、空白または空白がある場合に構文エラーを防ぎます。他のものは、すべての空白が単一のスペースに変換されるのを防ぎます。


1
接頭辞も見たことがあり[ "x$b" -eq "x" ]ますが、特に空の文字列をテストするために使用されたと思います。zshが使用する構文(zshexpnマンページの「PARAMETER EXPANSION」)を使用したいのですが、それらの移植性についてはよくわかりません。
John P


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

31
これがために良いです、数値の比較と割り当てていますが、文字列の比較と割り当てのためにそれを使用する場合には、予期しない結果が得られます.... (( ))扱いとして任意の/すべての文字列0
Peter.O

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

2
外部プログラムを保存:する代わりに、ブリットインを使用します。trueexec
トム・ヘイル

@ivan_pozdeev &&.. を使用||して、それらの間で失敗したコマンドをキャッチする方法はありますか?
トム・ヘイル

2
@TomHale No. &&および||定義により、それらの前のコマンド全体に適用されます。したがって、その前に2つのコマンドがある場合(それらがどのように組み合わされているかに関係なく)、それを一方にのみ適用して、もう一方に適用することはできません。フラグ変数を使って/ / ロジックをエミュレートできますが、/ / 適切なものがあるのになぜ迷惑をかけるのですか?ifthenelseifthenelse
ivan_pozdeev 2017年

14

letコマンドは、1つが必要となる基本的な演算子のほとんどをサポートしています。

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

当然、これは変数を割り当てる場合にのみ機能します。他のコマンドは実行できません。


24
これは((...))とまったく同じなので、算術式に対してのみ有効です
drAlberT

13

これは、割り当てる変数を1回指定するだけでよく、割り当てが文字列であるか数値であるかは関係ありません。

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

ちょっとした考え。:)


大きな欠点:の標準出力もキャプチャされ[ test ]ます。そのため、コマンドがstdoutに何も出力しないことを「知っている」場合にのみ、構造は安全に使用できます。
ivan_pozdeev

また、stackoverflow.com / questions / 3953645 / ternary-operator-in-bash /…と同じです。さらに、内部で引用符を使用して引用符をエスケープする必要があります。スペーストレラントバージョンはのようになりますVARIABLE="`[ test ] && echo \"VALUE_A\" || echo \"VALUE_B\"`"
ivan_pozdeev

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
非常に説明的です。とても完成しました。非常に冗長です。私が好きな3つのこと。;-)
ジェシーチザム

2
あるternバッシュの一部?Macにはないようです
非極性2017

4
ちょっと@太極者無極而生-これはbashスクリプトの名前です-上記の「tern」セクションを「tern」という名前のファイルに保存してからchmod 700 tern、同じフォルダーで実行します。これternで、ターミナルにコマンドが表示されます
Brad Parks

8

三項演算子のシェルスクリプトでは、次の3つの方法を使用できます。

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

Or

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

Or

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

これは実際に(具体的には、これらの3つの例の最初と2番目)、この質問に対する最も適切な答えです。
netpoetica 2018年

6

bashの3項条件文の構文も非常によく似ています。

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

残念ながら、これは数値でのみ機能します-私の知る限り。



4

同様の構文が必要な場合は、これを使用できます

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

これは整数でのみ機能します。あなたはそれをもっと簡単に書くことができますa=$(((b==5) ? : c : d))- $((...))計算の結果を別の変数に割り当てたいときだけ必要です。
codeforester 2018

2

ここにいくつかのオプションがあります:

1-それ以外の場合は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-ケースの回答にインスパイアされた、より柔軟で1行の使用法は次のとおりです。

 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

に答える: 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

「式」は$((式))と同等であることを覚えておいてください


0

配列を使用する文字列指向の代替:

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

出力:

13: IGNORE
14: REPLACE
15: IGNORE
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.