Apa sintaks dari kondisi kompleks di shell?

10

Jika ingin mengekspresikan tes berikut dalam shell (sh):

if ( a == 1 && ( b == 1 || b == 2 )) { ... }

Sejauh ini, yang terbaik yang bisa saya tulis adalah ini:

if [[ $a -eq 1 ]]; then
  if [[ $b -eq 1 || $b -eq 2 ]]; then
     ...
  fi
fi

Saya tidak tahu bagaimana cara menggabungkan && dan || dengan prioritas yang benar. Googling belum memberi saya jawaban apa pun (tutorial hanya memberikan contoh dasar, jika ada)

Apa sintaksis untuk menggabungkan keduanya jika menjadi satu?

Offirmo
sumber
1
Ada alasan untuk tidak menggunakan ksh? Maka kode awal Anda hanya akan membutuhkan satu pasang kurung lagi:if (( a == 1 && ( b == 1 || b == 2 ))); then :; fi
manatwork

Jawaban:

14

Perhatikan bahwa [[ ]]tidak ada dalam Bourne atau POSIX sh. Untuk shsintaks yang sebenarnya , ada beberapa cara untuk melakukan ini.

Hanya menggunakan satu [ ]pasangan

if [ 1 -eq "$a" -a \( 1 -eq "$b" -o 2 -eq "$b" \) ]; then
    # ...
fi

atau Menghindari POSIX -adan -oopsi 1

if [ 1 -eq "$a" ] && { [ 1 -eq "$b" ] || [ 2 -eq "$b" ]; }; then
    # ...
fi

1 Salah satu alasan untuk menghindari -adan -oportabilitas maksimum - tidak semua testatau [implementasi dapat menangani lebih dari 4 argumen, yang persis sama dengan apa yang Anda dapatkan jika Anda menghubungkan ekspresi dengan -adan -odan \( \).

jw013
sumber
Skrip saya memiliki #! / bin / sh shebang, dan shell default adalah ksh . Kenapa dia tidak digunakan?
Offirmo
2
@Offirmo Jika Anda mendeklarasikan skrip Anda /bin/sh, menulis skrip menggunakan fitur yang tidak ada salah sh. Anda harus menyadari bahwa kshBUKAN sh, tetapi superset dari BUKAN sh. Jika Anda membawa skrip ksh-tapi-dinyatakan-sebagai- shke sistem di mana shbukan symlink ksh, mungkin rusak. Anda dapat menghindari masalah itu dengan memastikan skrip Anda cocok dengan deklarasi.
jw013
Saya pikir pengaturan / bin / sh sebagai shebang akan membuat skrip saya dipanggil melalui / bin / sh . Apakah maksud Anda bahwa shell default saya (ksh) mengabaikan shebang dan menafsirkannya secara langsung?
Offirmo
@Offirmo Anda benar: shebang of /bin/shakan meminta /bin/sh. Masalahnya adalah /bin/shtidak menerima [[. Anda tidak dapat menggunakan [[atau menggunakan shell yang menerima [[, misalnya ksh, sebagai shebang Anda.
jw013
2
Masalahnya tidak sebanyak itu -a/ saya -otidak didukung oleh beberapa implementasi tetapi itu tidak dapat diandalkan untuk argumen sewenang-wenang. Suka [ "$a" = "$b" -o "$b" = "$c" ]akan gagal untuk nilai $asuka !dengan banyak [implementasi.
Stéphane Chazelas
2

Saya mencoba beberapa sintaks dan menemukan itu

if [[ $a -eq 1 ]] && [[ $b -eq 1 || $b -eq 2 ]]; then
 ...
fi

sedang bekerja.

Offirmo
sumber
1
ini bekerja untuk versi bash di atas 4.
Nikhil Mulley
2

Pendekatan POSIX lain:

if [ "$((a == 1 && ( b == 1 || b == 2 )))" -ne 0 ]; then
  ...
fi
Stéphane Chazelas
sumber
0

Cara yang tepat untuk melakukannya hanya dengan shell:

if test 1 -eq "$a" && test 1 -eq "$b" -o 2 -eq "$b"; then 
    ...
fi

Penjelasan:

testdi sini berfungsi sebagai tanda kurung dan -osebagai logis atau. Jika Anda seorang logis dan di dalam "kurung" Anda akan menggunakan -a.

Lebih lanjut tentang itu dapat ditemukan di sini

Omer Dagan
sumber