Üçlü operatör (? :) Bash


442

Böyle bir şey yapmanın bir yolu var mı

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

Bash mı kullanıyorsunuz?


1
@ dutCh cevabıbash "üçlü operatör" e benzer bir şeye sahip olduğunu gösterir, ancak bashbuna "koşullu operatör" denir expr?expr:expr( man bash"Aritmetik Değerlendirme" bölümüne bakın ). Unutmayın bash"koşullu operatör" zor ve bazı gotchas vardır.
Trevor Boyd Smith

Bash tamsayılar için üçlü bir operatöre sahiptir ve aritmetik ifadenin içinde çalışır ((...)). Bkz. Kabuk Aritmetiği .
codeforester

1
@Codeforester'ın belirttiği gibi üçlü operatör aritmetik genişleme $(( ))ve aritmetik değerlendirme ile çalışır (( )). Ayrıca bakınız https://mywiki.wooledge.org/ArithmeticExpression.
Kai

Yanıtlar:


490

Üçlü operatör ? :sadece kısa şeklidirif/else

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

Veya

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

103
=Operatörün sayısal eşitliği değil, dize eşitliğini test ettiğini (yani [[ 05 = 5 ]]yanlış olduğunu) unutmayın. Sayısal karşılaştırma istiyorsanız -eqbunun yerine kullanın.
Gordon Davisson

10
Bu daha kısa form varif/then/else
vol7ron

15
Üçlü operatör etkisi elde etmek için kısa devre davranışını kullanmanın dahice bir yolu :) :) :)
mtk

6
neden [[ve]]? şu şekilde çalışır: [$ b = 5] && a = "$ c" || a = "$ d"
kdubs

83
Yapının cond && op1 || op2doğasında bir hata vardır: op1herhangi bir nedenle sıfır dışında çıkış durumu varsa , sonuç sessizce olur op2. if cond; then op1; else op2; fiaynı zamanda bir satırdır ve bu kusuru yoktur.
ivan_pozdeev

375

Kod:

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

58
bu diğerlerinden daha iyidir ... üçüncül operatör ile ilgili nokta, bunun bir operatör olması, dolayısıyla uygun bağlamın bir ifadede olmasıdır, dolayısıyla bir değer döndürmesi gerekir.
nic ferrier

2
Bu en özlü yoldur. echo "$c"İle olan bölüm takma, çok satırlı bir komutsa ( echo 1; echo 2parantez), parantez içine almanız gerektiğini unutmayın.
Matt

2
Bu aynı zamanda test edilen komutun herhangi bir çıktısını da yakalayacaktır (evet, bu özel durumda, hiç üretmediğini "biliyoruz").
ivan_pozdeev

8
Bu işleçler zinciri yalnızca üçlü bir işleç gibi davranır ve sonrasındaki komutun &&sıfırdan farklı bir çıkış durumuna sahip olmayacağından eminseniz . Aksi takdirde, a && b || c "beklenmedik" çalışacak ceğer abaşarılı ama bbaşarısız olur.
chepner

155

Koşul yalnızca bir değişkenin ayarlanıp ayarlanmadığını kontrol ediyorsa, daha kısa bir form bile vardır:

a=${VAR:-20}

atayacağı adeğeri VARise VARayarlanır, aksi takdirde bu varsayılan değer atar20 - bu da bir ifadenin bir sonucu olabilir.

Yorumda alex'in belirttiği gibi, bu yaklaşıma teknik olarak "Parametre Genişletme" denir.


6
İçinde tire bulunan bir dize parametresi geçirilmesi durumunda, alıntı işaretleri kullanmak zorunda kaldım:a=${1:-'my-hyphenated-text'}
saranicole

1
tembel bağlantı - sadece yerine ( :-)
Justin Wrobel

10
@JustinWrobel - ne yazık ki hiçbir sözdizimi yok ${VAR:-yes:-no}.
Ken Williams

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

cond && op1 || op2Diğer yanıtlar önerilen ifadesi doğal bir hata vardır: eğer op1bir sıfırdan farklı çıkış durumları,op2 sessizce sonuç olur; hata ayrıca -emoda yakalanmayacaktır . Yani, bu ifade varsa kullanmak sadece güvenli olduğunu op1başarısız asla (örneğin :, truebölünme ve OS isteği) gibi (başarısız olabilir hiçbir işlem yapılmadan bir yerleşiği veya değişken atama ise).

Not ""tırnak. İlk çift $b, boş veya boşluk varsa bir sözdizimi hatasını önler . Diğerleri tüm boşlukların tek boşluklara çevrilmesini önleyecektir.


1
Ayrıca önek gördüm, [ "x$b" -eq "x" ]özellikle boş dize test etmek için kullanılan inanıyorum . Zsh (zshexpn manpage'de 'PARAMETER GENLEŞME') tarafından kullanılan sözdizimlerini kullanmayı seviyorum, ancak taşınabilirlikleri hakkında fazla bir şey bilmiyorum.
John P


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

31
Bu, sayısal karşılaştırmalar ve atamalar için iyidir , ancak dize karşılaştırmaları ve atamaları için kullanırsanız öngörülemeyen sonuçlar verir .... (( ))herhangi bir / tüm dizeleri şöyle davranır0
Peter.O

3
Bu ayrıca yazılabilir:a=$(( b==5 ? c : d ))
joeytwiddle

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

Bu, parçanın || kazara && ve || başarısız olur.


Bu hala -emoddaki hatayı yakalamayacaktır : (set -o errexit; [ 5 == 5 ] && { false; true; echo "success"; } || echo "failure"; echo $?; echo "further on";)->success 0 further on
ivan_pozdeev

2
Harici bir programı kaydetmek için :bulit-in kullanın . trueexec
Tom Hale

@ivan_pozdeev &&.. Kullanmanın ||ve aralarında başarısız bir komutu yakalamanın bir yolu var mı ?
Tom Hale

2
@TomHale No. &&ve ||tanım gereği, önlerindeki tüm komut için geçerlidir. Bu nedenle, ondan önce iki komutunuz varsa (nasıl birleştirildiklerine bakılmaksızın), komutları sadece birine değil diğerine uygulayamazsınız. / / Logic'i bayrak değişkenleriyle taklit edebilirsiniz , ancak / / uygunsa neden rahatsız edersiniz ? ifthenelseifthenelse
ivan_pozdeev

14

Let komutu destekler en fazla bir ihtiyaç duyduğu temel operatörlerin:

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

Doğal olarak, bu sadece değişkenlerin atanması için çalışır; diğer komutları çalıştıramaz.


24
tam olarak ((...)) ile eşdeğerdir, bu nedenle yalnızca aritmetik ifadeler için geçerlidir
drAlberT

13

Burada, yalnızca bir kez atadığınız değişkeni belirtmeniz gereken başka bir seçenek vardır ve atamanızın bir dize mi yoksa sayı mı olduğu önemli değildir:

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

Sadece bir düşünce. :)


Büyük bir dezavantaj: aynı zamanda stdout'u da yakalayacaktır [ test ]. Bu nedenle, yapı yalnızca komutun stdout'a herhangi bir çıktı vermediğini "biliyorsanız" güvenlidir.
ivan_pozdeev

Ayrıca stackoverflow.com/questions/3953645/ternary-operator-in-bash/… artı aynı teklifleri alıntı ve kaçış ihtiyacı. Uzay toleranslı sürüm gibi görünecektir VARIABLE="`[ test ] && echo \"VALUE_A\" || echo \"VALUE_B\"`".
ivan_pozdeev

8

Kullanım durumlarım için aşağıdakiler işe yarıyor gibi görünüyor:

Örnekler

$ tern 1 YES NO                                                                             
YES

$ tern 0 YES NO                                                                             
NO

$ tern 52 YES NO                                                                            
YES

$ tern 52 YES NO 52                                                                         
NO

ve şöyle bir komut dosyasında kullanılabilir:

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

deniz kırlangıcı

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
Çok açıklayıcı. Çok eksiksiz. Çok ayrıntılı. Sevdiğim üç şey. ;-)
Jesse Chisholm

2
olduğu ternBash parçası? Mac'de öyle görünmüyor
nonopolarity

4
hey @ 太極 者 無極 而 生 - bash betiğinin adı bu - yukarıdaki "sumru" bölümünü "sumru" adlı bir dosyaya kaydedin, ardından chmod 700 ternaynı klasörde çalıştırın . Şimdi ternterminalinizde bir komut olacak
Brad Parks

8

Üçlü operatör için Shell Scripting'de aşağıdaki üç yolu kullanabiliriz:

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

Or

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

Or

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

Bu aslında (bu üç örneğin birinci ve ikinci olarak) bu soruya en uygun cevaptır IMHO.
netpoetica

6

Ayrıca bash'daki üçlü şartlar için çok benzer bir sözdizimi vardır:

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

Ne yazık ki, sadece sayılarla çalışıyor - bildiğim kadarıyla.


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

4

Benzer bir sözdizimi istiyorsanız bunu kullanabilirsiniz

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

Bu yalnızca tamsayılarla çalışır. Sadece aritmetik sonucunu başka bir değişkene atamak istediğimizde a=$(((b==5) ? : c : d))- $((...))gerektiği gibi daha basit yazabilirsiniz .
codeforester

2

İşte bazı seçenekler:

1- Eğer bir satırda başka bir satır varsa kullanın.

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

2- Böyle bir fonksiyon yazın:

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

betiğin içinde böyle kullan

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

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

3- Dava cevabından esinlenerek daha esnek ve tek hat kullanımı:

 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

İşte genel bir çözüm,

  • string testleri ile de çalışır
  • bir ifade gibi hissettiriyor
  • durum başarısız olduğunda herhangi bir ince yan etkiyi önler

Sayısal karşılaştırma ile test

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

Dize karşılaştırması ile test

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


1

Bu Vladimir'in iyi cevabı gibidir . "Üçlü" ifadeniz "eğer true, string, false, empty" ise, o zaman şunları yapabilirsiniz:

$ 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

cevaplamak için: int a = (b == 5) ? c : d;

sadece yaz:

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

"ifade" nin $ ((ifade)) ile eşdeğer olduğunu unutmayın


0

Bir dizi kullanan dizeye yönelik bir alternatif:

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

hangi çıktılar:

13: IGNORE
14: REPLACE
15: IGNORE
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.