İfade aritmetiğindeki parantez: 3 * (2 + 1)


60

expr Parantez gibi gözükmüyor (matematikte operatörün önceliğini açıklamak için kullanılıyor):

expr 3 * (2 + 1)
bash: syntax error near unexpected token `('

Operatör önceliği bash olarak nasıl ifade edilir?

Yanıtlar:


40

letBash yerleşikini kullanmanın başka bir yolu :

$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9

Not

As @ Stéphane Chazelas işaret de, bashkullanmanız gereken ((...))üzerinde aritmetik yapmak exprveya letokunabilirlik için.

Taşınabilirlik için, @Bernhard answer$((...)) gibi kullanın .


1
+1 Daha da okunabilir! Sadece Linux kullanıcıları için faydalı olacağını düşünerek soruma cevap yazdım, fakat şimdi diğer cevaplardan çok faydalanıyorum :-)
Nicolas Raoul

3
Kullanmak için hiçbir sebep yok let. Bundan daha standart veya taşınabilir değildir (( a = 3 * (2 + 1) ))(her ikisi de gelir kshve sadece ksh, bash ve zsh olarak bulunur) ve daha az okunaklı veya alıntı kolaydır. a=$((3 * (2 + 1)))Taşınabilir olmak için kullanın .
Stéphane Chazelas,

2
Yanlış olduğunu söylemiyorum, sadece daha iyi alternatifler olduğu için kullanılmaması gerektiğini söylüyorum (biri okunabilirlik ((a = 3 * (2 + 1) )), biri taşınabilirlik için a=$((3 * (2 + 1)))), bu yüzden size veya cevabınıza karşı bir not değil, seçili cevap olmasına karşı bir not değil. ve en skorer.
Stéphane Chazelas 12:14

@ StéphaneChazelas: Cevabım güncellendi!
cuonglm

Her zaman a=1 $[a+2]ya da kullandım a=1 b=2 $[a+b]. Sebepleri bu sözdiziminden sakınmak mı?
Gordon,

74

Bunun yerine aritmetik genişlemeyi kullanabilirsiniz.

echo "$(( 3 * ( 2 + 1 ) ))"
9

Benim düşünceme göre, bu kullanmaktan daha hoş görünüyor expr.

itibaren man bash

Aritmetik Genişleme Aritmetik genişleme, bir aritmetik ifadenin değerlendirilmesine ve sonucun değiştirilmesine olanak sağlar. Aritmetik genişleme formatı şudur:

         $((expression))

İfade, çift tırnak içine alınmış gibi ele alınır, ancak parantez içindeki çift tırnak işareti özel olarak ele alınmaz. İfadedeki tüm simgeler, parametre genişletme, dize genişletme, komut değiştirme ve alıntı kaldırma işleminden geçer. Aritmetik genişlemeler iç içe geçmiş olabilir.

Değerlendirme, ARİTMETİK DEĞERLENDİRME altında aşağıda listelenen kurallara göre yapılır. İfade geçersizse bash, başarısızlık olduğunu belirten bir ileti yazdırır ve ikame yapılmaz.


1
Okunabilirliğin yanı sıra, aritmetik işlem için fazladan bir işlem gerektirmez; kabuğun kendisi tarafından idare edilir.
chepner

POSIX mermilerinde kelime bölme işlemine tabi olduğunu, bu yüzden liste bağlamında alıntı yapmak için iyi bir alışkanlık olduğunu unutmayın.
Stéphane Chazelas,

Bunu bash kabuğunda denediğimde 'Yasadışı değişken adı. "
lordhog

40

exprModern mermilerde aritmetik kullanmanın bir nedeni yok .

POSIX, $((...))genişletme operatörünü tanımlar . Yani tüm POSIX uyumlu mermilerde kullanabilirsiniz ( shtüm modern Unix severler, çizgi, bash, yash, mksh, zsh, posh, ksh ...).

a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))

kshAyrıca let, aynı aritmetik ifadenin türünden geçen, bir şeye genişlemeyen ancak ifadenin 0'a dönüp gitmediğine bağlı olarak bir çıkış durumu döndürür expr:

if let 'a = 3 * (2 + 1)'; then
  echo "$a is non-zero"
fi

Bununla birlikte, alıntılar garip ve çok okunaklı olmadığından expr(elbette ki aynı ölçüde değil ), alternatif bir form kshda ortaya koydu ((...)):

if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
  echo "$a is non-zero and 3 > 1"
fi
((a+=2))

çok daha okunaklı olan ve bunun yerine kullanılması gereken.

letve ((...))sunulduğunu ksh, zshve bash. $((...))Sözdizimi diğer kabukları taşınabilirliği gerekli olup olmadığını, tercih edilmelidir exprsadece önceden POSIX Bourne gibi kabuklar (tipik olarak Bourne kabuk veya Almquist kabuğun ilk versiyonları) için gereklidir.

Bourne dışı cephesinde, yerleşik aritmetik işleci olan birkaç kabuk vardır:

  • csh/ tcsh(aslında yerleşik aritmetik değerlendirmeli ilk Unix kabuğu):

    @ a = 3 * (2 + 1)
  • akanga(dayanarak rc)

    a = $:'3 * (2 + 1)'
  • Tarihsel bir not olarak, 1989'da usenet'te yayınlanan Almquist kabuğunun orijinal versiyonunun bir yerleşimi vardı expr(aslında birleşti test), ancak daha sonra kaldırıldı.


Senden her gün yeni bir şey öğreniyorum Stéphane. POSIX kabuk bilginizi çok takdir ediyorum!
MattBianco

Nasıl hakkında : $((a = a*2))?
Arthur2e5,

Kayan nokta varsa ne olur? İfadem = = ((-14 + 0.2 * (1 + 2 + 3))). Hata belirteci ".2 * (1 + 2 + 3)"
Blaise

@ Blaise, o zaman $((...))zsh, ksh93 veya yash gibi kayan noktaları destekleyen bir kabuğa ihtiyacınız olacak .
Stéphane Chazelas

16

exprharici bir komuttur, özel bir kabuk sözdizimi değildir. Bu nedenle, exprözel karakterler kabuğu görmek istiyorsanız , bunları alıntı yaparak kabuk ayrıştırmalarına karşı korumanız gerekir. Ayrıca, exprher numaraya ve operatöre ayrı bir parametre olarak geçilmesi gerekir. Böylece:

expr 3 \* \( 2 + 1 \)

1970'lerden veya 1980'lerden kalma bir antik unix sistemi üzerinde çalışmadığınız sürece, kullanmanız için çok az neden vardır expr. Eski günlerde, mermilerin aritmetik işlem yapması için yerleşik bir yolu yoktu ve exprbunun yerine yardımcı programı aramanız gerekiyordu . Tüm POSIX mermileri, aritmetik genişleme sözdizimi ile yerleşik aritmetik özelliklerine sahiptir .

echo "$((3 * (2 + 1)))"

Yapı $((…)), aritmetik ifadenin sonucuna genişler (ondalıkta yazılır). Bash, çoğu kabuk gibi, sadece tamsayı aritmetik modulo 2 64'i (ya da bash'ın eski sürümleri için ve 32-bit makinelerde diğer bazı kabukları için modulo 2 32 ) destekler.

Bash ödevler yapmak veya bir ifadenin 0 olup olmadığını test etmek, ancak sonucu umursamamak istediğinizde ek bir kolaylık sözdizimi sunar . Bu yapı aynı zamanda ksh ve zsh da mevcuttur, fakat düz sh de değildir.

((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then 

Tamsayı aritmetiğine ek olarak, exprbirkaç dize işleme işlevi sunar. Bunlar da POSIX kabuklarının özellikleri ile kapsanıyor: bunlardan biri hariç: expr STRING : REGEXPdizenin belirtilen regexp ile eşleşip eşleşmediğini test eder. Bir POSIX kabuğu bunu harici araçlar olmadan yapamaz, ancak bash ile yapabilir [[ STRING =~ REGEXP ]]( farklı bir regexp sözdizimi ileexprklasik bir araçtır ve BRE'yi kullanır, bash ERE'yi kullanır).

20 yıllık sistemlerde çalışan komut dosyalarını sürdürmüyorsanız, bunun exprvarolduğunu bilmenize gerek yoktur . Kabuk aritmetiği kullanın.


expr foo : '\(.\)'ayrıca metin çıkarımı yapar. bash'nin BASH_REMATCHbenzer bir şey başarır. Ayrıca, POSIX'in yapmadığı string karşılaştırması da yapar [( sortbunun için nasıl kullanılacağını hayal edebilmesine rağmen ).
Stéphane Chazelas 15:14

sözdizimi yer tutucu olarak alt çizgi --- siz bir Schemer, @Giles? :]
RubyTuesdayDONO

1
@RubyTuesdayDONO Burada alt çizgi kullanmıyordum. U + 2026 HORIZONTAL ELLIPSIS’i yanlış mı okuyorsunuz? Eğer öyleyse, daha büyük bir font kullanmayı deneyin.
Gilles 'SO- kötülük'

@Giles - tamam, evet, yalnızca yazı tipi boyutumdan dolayı alt çizgi gibi görünüyor. benim için, "Schemer" bir tamamlayıcıdır ve elipslere karşı değil, alt çizginin anlamını değiştirmesine rağmen hiçbir şekilde anlamını değiştirmez… bunun üzerine sinsice yaklaşmaya gerek yok: /
RubyTuesdayDONO

12

Parantezleri tırnak işaretleri ile kullanın:

expr 3 '*' '(' 2 '+' 1 ')'
9

Tırnaklar bash'ın parantezi bash sözdizimi olarak yorumlamasını önler.


2
Nicolas'ın gösterdiği ancak açıklamadığı şey, exprkomut satırındaki belirteçlerin boşluklarla ayrılması gerektiğidir; yani; örneğin, expr 3 "*" "(2" "+" "1)" işe yaramayacak . (Ayrıca, BTW, muhtemelen alıntı yapmak gerekmez +.)
G-Man

Parantezler gibi anahtar kelimeler değildir whileve [[bunlar sözdizimidir. Anahtar kelimeler olsalardı, komut argümanlarında olduğu gibi yorumlanmayacaktı. Alıntıların ayrıştırmaması, ancak bunun yerine bir string değişkeni görmesi için tırnaklara ihtiyacınız var.
Gilles 'SO- kötülük olmayı bırak'

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.