case + sözdizimi durumunda eşit veya daha az veya daha büyük nasıl uygulanır


9

Hedefim bir sayı aralığını (yalnızca case+ ile esac) doğrulamak ve aralığı yazdırmaktır. Yani mesela:

  • Sayı 0 ile 80 arasındaysa, yazdırın >=0<=80
  • Sayı 81 ile 100 arasındaysa, yazdırın >=81<=100
  • vb.

Aşağıdaki komut dosyamdaki sorun >=0<=90yalnızca 0 ile 9 arasındaki sayılarda yazdırılıyor. Kodumu nasıl düzeltebilirim, böylece sayı aralığına göre doğru çıktıyı yazdıracak mı?

#!/bin/ksh
read number 
case $number in 
 [0-80])  echo ">=0<=80";; 
 [81-100]) echo ">=81<=100";; 
 [101-120]) echo ">=101<=120";;
 [121-300]) echo ">=121<=300";;
esac

Yanıtlar:


6

caseSadece desen eşleştirme, bu aritmetik değerlendirme yapmayacağım edilir (eğer düşünün belki hariç zsh'ın <x-y>genişletilmiş desen eşleştirme operatörü). [...]Sadece maç için bir (ya da karakter harmanlama elemanı içinde belirtilen grubu göre bazı uygulamalarda). Yani örneğin [0-80]eşleşecektir bir o biri ise karakter 0için 8ya da 0(olduğundan, bir 0, 1, 2, 3, 4, 5, 6, 7, 8).

Sayıları aşağıdaki gibi desenlerle eşleştirebilirsiniz:

case $(($number)) in
  ([0-9]|[1-7][0-9]|80) echo ">=0<=80";;
  (8[1-9]|9[0-9]|100) echo ">=81<=100";;
  ... and so on
esac

Ancak bunun doğru araç olmadığını kolayca görebilirsiniz.

[...]Maçları biri , belirtilen karakter listesine göre karakterini böylece [121-300]o aynı nedenle, 1, 2, 1-3, 0 veya 0 olan herhangi bir karakter için kibrit [0-3]veya [0123].

kullanın:

if [ "$number" -ge 0 ] && [ "$number" -le 80 ]; then
  echo ">=0<=80"
elif [ "$number" -ge 81 ] &&  [ "$number" -le 100 ]; then
  echo ">=81<=100"
elif ... and so on
  ...
fi

Kullanmanın başka bir yolu caseşöyle olacaktır:

case $((
  (number >= 0 && number <= 80)   * 1 +
  (number > 80 && number <= 100)  * 2 +
  (number > 100 && number <= 120) * 3 +
  (number > 120 && number <= 300) * 4)) in
  (1) echo ">=0<=80";;
  (2) echo ">=81<=100";;
  (3) echo ">=101<=120";;
  (4) echo ">=121<=300";;
  (0) echo "None of the above";;
esac

Veya üçlü operatörü ( x ? y : z) kullanın:

case $((
  number >= 0 && number <= 80   ? 1 :
  number > 80 && number <= 100  ? 2 :
  number > 100 && number <= 120 ? 3 :
  number > 120 && number <= 300 ? 4 : 0)) in...

Ya da @mikeserv gibi, kutunun dışında düşünün , casemantığı tersine çevirin ve 1bu aritmetik karşılaştırmaların değeriyle eşleştirin .


1
+1, düşünün if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - else. Daha az yazım, daha az hataya açık.
peterph

@peterph Ayrıca çalışması daha uzun sürer.
Ken Sharp

4

Aslında bunu yapmak gerçekten çok kolay. Bununla ilgili olan şey case, her zaman bir desene karşı ilk eşleşmeyi bulmak için gereken kadar genişleyeceğidir. Bu davranış. Ve böylece sadece bilinen bir dizeyle kurabilir ve desenlerin genişlemelerini değerlendirebilirsiniz.

case  1:${number:--} in
(1:*[!0-9]*|1:0*[89]*)
  ! echo NAN
;;
($((number<81))*)
    echo "$number >=0<=80"
;;
($((number<101))*)
    echo "$number >=81<=100"
;;
($((number<121))*)
    echo "$number >=101<=120"
;;
($((number<301))*)
    echo "$number >=121<=300"
;;
esac

casekalıpta bir tane önde 1 bulmak için bu kalıplardan daha fazlasını genişletmeyecektir. Bu, özellikle kullanıcı girdisi ile çalışırken önemlidir, çünkü $numberaslında bir matematik genişletmesine koyduğunuz aynı durum ifadesinde onu aritmetik bir genişletme bağlamına koymaya çalışmadan önce içeriğini güvenli bir şekilde doğrulayabileceğiniz anlamına gelir .


Box Kutunun dışında / etrafında düşünme şeklini seviyorum.
Stéphane Chazelas

@ StéphaneChazelas - seviyorum case. $((matematikle yapabileceğiniz bazı harika şeyler ))ve case- özellikle ihtiyaç duyulana kadar asla desenlerde olmayan çevre ödevleri - ve desenleri bir aliaszincirle doldurursanız iç içe yinelemeleri genişleten ayrıştırma ağaçları bile oluşturabilirsiniz . karakter çevirisi gibi şeyler yapmak ve bayt değerleri için karakter takas için bir kabuk almak için buldum en hızlı yolu. oldukça hızlı olabilir - C-Locale ASCII + <> sekizli en kötü durum 7 temel POSIX paterni genişletmesidir.
mikeserv

1

Bu çok hoş değil ama bunu kullanabilirsiniz:

 #!/bin/ksh

read number  

case $number in
[0-9]|[1-7][0-9]|80) echo  echo ">=0<=80";;
8[1-9]|9[0-9]|100) echo ">=81<=100";;
10[1-9]|11[0-9]|120) echo ">=101<=120";;
12[1-9]|130) echo ">=121<=300";;
esac

"001" veya "0x99" gibi sayıları kapsamak için sayıyı $ (($ $)) ile "onaylamak" isteyebilirsiniz ... Bu, aynı zamanda "12" ve "12 + 12" için de geçerlidir. arzu edilmez.
Stéphane Chazelas
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.