Birden çok mantıksal işleç, ((A || B) && C) ve “beklenmedik belirteci yakınında sözdizimi hatası”


24

Bash 3 ile çalışıyorum ve şartlı bir şeyler oluşturmaya çalışıyorum. C / C ++, onun ölü basit: ((A || B) && C). Bash’te ortaya çıkması böyle değil (Git yazarlarının diğer çabalara geçmeden önce bu koda katkıda bulunmaları gerektiğini düşünüyorum).

Bu çalışmıyor. <0 or 1>Bir dize değişmez olduğunu unutmayın ; 0 veya 1 anlamına gelir (genellikle gelir grep -i).

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi

Bu sonuçlanır:

line 322: syntax error near unexpected token `[['

Sonra denedim:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi

sonuçlanır:

line 322: syntax error near unexpected token `[['

Sorunun bir kısmı, arama sonuçlarının önemsiz örnekleridir ve bileşik koşulluların daha karmaşık örnekleri değildir.

((A || B) && C)Bash'te basit bir işlemi nasıl yapabilirim ?


Sadece onu açmaya ve aynı komutları birden fazla blok halinde tekrarlamaya hazırım:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>

if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then
    ...
elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then
    ... 
fi

Yanıtlar:


42

Bash sözdizimi, bir kısmı C'den ilham alsa bile, C-benzeri değildir, basitçe C kodunu yazmayı deneyebilir ve çalışmasını bekleyemezsiniz.

Bir kabuğun ana noktası komutları çalıştırmaktır. Açık-braket komutu [, tek bir test gerçekleştiren bir komuttur¹. Hatta test(son kapanış dirseği olmadan) olarak bile yazabilirsiniz . ||Ve &&operatörleri birleştirmek, kabuk operatörleri komutlarını , test değil.

Yani yazarken

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]

olarak ayrıştırıldı

[ [ "$A" -eq "0" ] ||
[ "$B" -ne "0" ] ] &&
[ "$C" -eq "0" ]

hangisi aynı

test [ "$A" -eq "0" ||
test "$B" -ne "0" ] &&
test "$C" -eq "0"

Dengesiz parantez dikkat edin? Evet, bu iyi değil. Parantez ile girişiminde aynı sorun var: sahte parantez.

Komutları gruplamak için kullanılan sözdizimi parantezdir. Parantezlerin ayrıştırılması, onlardan önce tam bir komut gerektirdiğinden, parantez içindeki komutu yeni bir satır veya noktalı virgülle sonlandırmanız gerekir.

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then 

Çift parantez kullanmak için alternatif bir yol var. Tek parantezlerin aksine, çift parantezler özel kabuk sözdizimidir. Koşullu ifadeleri sınırlandırırlar . Çift parantez İçinde, parantez ve benzeri kullanabilirsiniz &&ve ||. İkili parantez kabuk sözdizimi olduğundan, kabuk bu operatörler parantez içinde olduğunda, normal kabuk komut sözdiziminin bir parçası değil koşullu ifade sözdiziminin bir parçası olduklarını bilir.

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then 

Tüm testleriniz sayısal ise, aritmetik ifadeleri sınırlayan başka bir yol daha vardır . Aritmetik ifadeler, C benzeri bir sözdizimi ile tamsayı hesaplamaları yapar.

if (((A == 0 || B != 0) && C == 0)); then 

Bash braket primerimi kullanışlı bulabilirsin .

[sh içinde kullanılabilir. [[ve ((bash'e (ve ksh ve zsh) özgüdür.

¹ Ayrıca boolean operatörleri ile birden testleri birleştirebilirsiniz, ancak bu kullanmak zahmetlidir ve bunu açıklayamam böylece ince tuzaklar vardır.


Sağol Giles. Bu, Bash 2 için Bash 4 ile devam ediyor mu? Ben hafif taşınabilirlik şey lazım ama Kusalananda ben edildi bazı şeyler söz değil yapıyor taşınabilir (yani ne yapıyorum olduğunu belirtmez değil taşınabilir?). Burada, hafifçe Bash 2 ila Bash 4 anlamına gelir.

[[ … ]]bash 2.02'de jww eklendi. ((…))bash 2.0'da eklendi.
Gilles 'SO- kötü olmayı bırak'

@Giles - teşekkürler. Bash 2 muhtemelen çoğuna gülünçtür. Bunun nedeni yönetişimimiz ve eski platformları terk etme isteksizliğimizdir. Bash 2 ve GCC 3, Fedora 1 testimizde ortaya çıktı. Daha eski bir platformun zaman zaman devam etmesine izin vereceğiz, ancak bunun için sebepler olmalı. Apple, Microsoft, Mozilla, vb. Gibi abandonware politikasına abone değiliz.

@jww Bunun öncelik lütfen anlayışla ||ve &&gelen değişim [için [[ve ((. Eşit öncelik olarak [(kullanımı parantez değerlendirme sırasını kontrol etmek için), fakat daha yüksek bir öncelik && sahiptir [[ve ((daha ||(C gibi).

6

Kullanım [[:

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...

İsterseniz [aşağıdakiler çalışır:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ...

3

Kullanım -oyerine iç içe || operatörü. -aDiğer ifadelerinizde gerekirse && işaretini de kullanabilirsiniz .

   EXPRESSION1 -a EXPRESSION2
          both EXPRESSION1 and EXPRESSION2 are true

   EXPRESSION1 -o EXPRESSION2
          either EXPRESSION1 or EXPRESSION2 is true


if [  "$A" -eq "0" -o "$B" -ne "0"  ] && [ "$C" -eq "0" ]; then echo success;fi

Teşekkürler. Karşılaştığım -ave -oonlarla çalışmadım. Yığın Taşması Üzerine Birisi Bunu Önlemek İçin Dedi. Senaryoyu kullanarak daha az okunabilir olduğundan çoğunlukla onlarla anlaştım.

... ama daha taşınabilir.
Kusalananda

@Kusalananda - Taşınabilirlik konusundaki liderler için teşekkür ederiz. Komut Will Bash 4. aracılığıyla Bash 2 sistemlerde çalışmalıdır [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]üzerlerinde sorun var?

Devamlı tuttuğunuzda bashveya anladığınız herhangi bir kabuğunda sorun yaşamayacaksınız [[ ... ]].
Kusalananda
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.