Operator logis sederhana di Bash

256

Saya memiliki beberapa variabel dan saya ingin memeriksa kondisi berikut (ditulis dalam kata-kata, maka upaya gagal saya dalam bash scripting):

if varA EQUALS 1 AND ( varB EQUALS "t1" OR varB EQUALS "t2" ) then 

do something

done.

Dan dalam upaya saya yang gagal, saya datang dengan:

if (($varA == 1)) && ( (($varB == "t1")) || (($varC == "t2")) ); 
  then
    scale=0.05
  fi
Amit
sumber

Jawaban:

682

Apa yang Anda tulis sebenarnya hampir berhasil (itu akan berhasil jika semua variabel adalah angka), tetapi itu sama sekali bukan cara yang idiomatis.

  • (…)tanda kurung menunjukkan sebuah subkulit . Apa yang ada di dalamnya bukan ekspresi seperti dalam banyak bahasa lain. Ini daftar perintah (seperti tanda kurung di luar). Perintah-perintah ini dieksekusi dalam subproses yang terpisah, sehingga setiap pengalihan, penugasan, dll yang dilakukan di dalam tanda kurung tidak memiliki efek di luar tanda kurung.
    • Dengan tanda dolar terkemuka, $(…)adalah substitusi perintah : ada perintah di dalam tanda kurung, dan output dari perintah digunakan sebagai bagian dari baris perintah (setelah ekspansi tambahan kecuali substitusi berada di antara tanda kutip ganda, tapi itu cerita lain ) .
  • { … }kurung kurawal seperti tanda kurung di mana mereka mengelompokkan perintah, tetapi mereka hanya memengaruhi parsing, bukan pengelompokan. Program ini x=2; { x=4; }; echo $xmencetak 4, sedangkan x=2; (x=4); echo $xcetakan 2. (Kawat gigi juga membutuhkan ruang di sekitar mereka dan titik koma sebelum ditutup, sedangkan kurung tidak. Itu hanya sintaks sintaksis.)
    • Dengan tanda dolar terkemuka, ${VAR}adalah ekspansi parameter , yang meluas ke nilai variabel, dengan kemungkinan transformasi tambahan.
  • ((…))tanda kurung ganda mengelilingi instruksi aritmatika , yaitu, perhitungan pada bilangan bulat, dengan sintaksis yang menyerupai bahasa pemrograman lain. Sintaks ini sebagian besar digunakan untuk penugasan dan dalam kondisi.
    • Sintaks yang sama digunakan dalam ekspresi aritmatika $((…)), yang diperluas ke nilai integer ekspresi.
  • [[ … ]]kurung ganda mengelilingi ekspresi bersyarat . Ekspresi bersyarat sebagian besar dibangun pada operator seperti -n $variableuntuk menguji apakah suatu variabel kosong dan -e $fileuntuk menguji apakah ada file. Ada juga operator kesetaraan string: "$string1" == "$string2"(berhati-hatilah bahwa sisi kanan adalah sebuah pola, mis. [[ $foo == a* ]]Tes jika $foodimulai dengan asementara [[ $foo == "a*" ]]tes jika $footepat a*) !, &&dan ||operator , dan operator untuk negasi, konjungsi dan disjungsi serta tanda kurung untuk pengelompokan. Perhatikan bahwa Anda memerlukan ruang di sekitar setiap operator (mis [[ "$x" == "$y" ]]. Tidak [[ "$x"=="$y" ]]), dan spasi atau karakter seperti ;di dalam dan di luar tanda kurung (misalnya [[ -n $foo ]], tidak[[-n $foo]]).
  • [ … ]kurung tunggal adalah bentuk alternatif dari ekspresi kondisional dengan lebih banyak quirks (tetapi lebih tua dan lebih portabel). Jangan menulis apa pun untuk saat ini; mulai khawatir tentang mereka ketika Anda menemukan skrip yang mengandungnya.

Ini adalah cara idiomatis untuk menulis tes Anda di bash:

if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then

Jika Anda membutuhkan portabilitas ke shell lain, ini akan menjadi caranya (perhatikan kutipan tambahan dan kurung terpisah di sekitar setiap tes individu, dan penggunaan =operator tradisional daripada ==varian ksh / bash / zsh ):

if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then
Gilles 'SANGAT berhenti menjadi jahat'
sumber
31
Pos yang bagus, ringkasan tanda kurung hanya ideal.
KomodoDave
10
Lebih baik digunakan ==untuk membedakan perbandingan dari menetapkan variabel (yang juga =)
Will Sheppard
1
Oh, maksudku kurung tunggal (bulat), maaf atas kebingungannya. Yang di dalam [[ $varA = 1 && ($varB = "t1" || $varC = "t2") ]]tidak memulai sub proses meskipun poin pertama secara eksplisit mengatakan: "Apa yang ada di dalam [tanda kurung] bukan ekspresi seperti dalam banyak bahasa lain" - tetapi pasti ada di sini! Itu mungkin jelas bagi bash wiz yang berpengalaman, tetapi bahkan tidak bagi saya, segera. Kebingungan dapat muncul karena tanda kurung tunggal dapat digunakan dalam sebuah ifpernyataan, hanya saja tidak dalam ekspresi di dalam tanda kurung ganda.
Peter - Reinstate Monica
2
@ protagonist ==tidak benar-benar "lebih idiomatis" daripada =. Mereka memiliki arti yang sama, tetapi ==merupakan varian ksh juga tersedia dalam bash dan zsh, sedangkan =portabel. Sebenarnya tidak ada keuntungan menggunakan ==, dan itu tidak bekerja di sh polos.
Gilles 'SANGAT berhenti menjadi jahat'
2
@ WillSheppard Sudah ada banyak perbedaan lain antara perbandingan dan penugasan: perbandingan ada di dalam kurung, penugasan tidak; perbandingan memiliki ruang di sekitar operator, tugas tidak; tugas memiliki nama variabel di sebelah kiri, perbandingan jarang memiliki sesuatu yang tampak seperti nama variabel di sebelah kiri dan Anda tetap bisa dan harus memberi tanda kutip. Anda dapat menulis ==di dalam [[ … ]], jika Anda mau tetapi =memiliki keuntungan juga bekerja di dalamnya , [ … ]jadi saya sarankan untuk tidak membiasakan diri menggunakan ==sama sekali.
Gilles 'SO- stop being evil'
34

sangat dekat

if [[ $varA -eq 1 ]] && [[ $varB == 't1' || $varC == 't2' ]]; 
  then 
    scale=0.05
  fi

harus bekerja.

memecahnya

[[ $varA -eq 1 ]] 

adalah perbandingan integer dimana

$varB == 't1'

adalah perbandingan string. kalau tidak, saya hanya mengelompokkan perbandingan dengan benar.

Kurung kotak ganda membatasi Ekspresi Bersyarat. Dan, saya menemukan yang berikut ini sebagai bacaan yang baik pada subjek: "(IBM) Demystify test, [, [[, ((and and-then-else"

cocok
sumber
Hanya untuk memastikan: Mengutip 't1'tidak perlu, kan? Karena berbeda dengan instruksi aritmatika dalam tanda kurung ganda, di mana t1akan menjadi variabel, t1dalam ekspresi kondisional dalam tanda kurung ganda hanyalah string literal. Yaitu, [[ $varB == 't1' ]]persis sama dengan [[ $varB == t1 ]], kan?
Peter - Reinstate Monica
6

Versi yang sangat portabel (bahkan untuk legacy bourne shell):

if [ "$varA" = 1 -a \( "$varB" = "t1" -o "$varB" = "t2" \) ]
then    do-something
fi

Ini memiliki kualitas tambahan hanya dengan menjalankan satu subproses paling banyak (yang merupakan prosesnya [), apa pun rasanya.

Ganti =dengan -eqjika variabel berisi nilai numerik, mis

  • 3 -eq 03 itu benar, tapi
  • 3 = 03itu salah. (perbandingan string)
JP Tosoni
sumber
3

Ini adalah kode untuk versi pendek pernyataan if-then-else:

( [ $a -eq 1 ] || [ $b -eq 2 ] ) && echo "ok" || echo "nok"

Perhatikan hal-hal berikut:

  1. ||dan &&operan di dalam jika kondisi (yaitu antara kurung bulat) adalah operan logis (atau / dan)

  2. ||dan &&operan luar jika kondisinya berarti / lain

Secara praktis pernyataan itu mengatakan:

jika (a = 1 atau b = 2) maka "ok" else "nok"

tlc
sumber
Parenthesis ( ... )menciptakan subkulit. Mungkin ingin menggunakan kawat gigi { ... }sebagai gantinya. Status apa pun yang dibuat dalam subkulit tidak akan terlihat di pemanggil.
Clint Pachl
0
if ([ $NUM1 == 1 ] || [ $NUM2 == 1 ]) && [ -z "$STR" ]
then
    echo STR is empty but should have a value.
fi
AlikElzin-kilaka
sumber