Üç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.