[[dan persamaan kasus dalam bash

13

Apakah

if [[ "$1" = pattern ]]; then
    hook
fi

selalu berperilaku sama dengan

case "$1" in
    pattern) hook;;
esac

atau ada gotcha?

PSkocik
sumber
1
Saya tidak dapat menemukan kasus di mana mereka berbeda, terlepas dari shoptpengaturan dan nilai di $1atau pattern, atau $?sesudahnya. Satu-satunya perbedaan adalah bahwa $1tidak diperluas dalam output saat berjalan di bawah xtrace.
Kusalananda

Jawaban:

7

Ya, mereka hampir setara.


Detail

Di dalam sebuah [ … ]konstruksi:

The =operator (atau bahkan pilihan non-POSIX dari ==) tes pencocokan string, bukan pencocokan pola.

Di dalam sebuah [[ ]]konstruk (dari man bash):

Ketika operator == dan! = Digunakan, string di sebelah kanan operator dianggap sebagai pola dan cocok dengan aturan yang dijelaskan di bawah di bawah Pencocokan Pola . Jika opsi shell nocasematch diaktifkan, pertandingan dilakukan tanpa memperhatikan kasus karakter alfabet. Nilai kembali adalah 0 jika string cocok (==) atau tidak cocok (! =) Polanya, dan 1 sebaliknya. Bagian mana pun dari pola dapat dikutip untuk memaksa agar dicocokkan sebagai string.

Di dalam sebuah casekonstruk (dari man bash, diedit dan penekanan milikku):

kata dalam daftar [[(] pola [| pola] ...) ;; ] ... esac
... mencoba mencocokkannya dengan masing-masing pola secara bergantian, menggunakan aturan pencocokan yang sama seperti untuk ekspansi pathname (lihat Perluasan Pathname di bawah). ... Setiap pola yang diperiksa diperluas menggunakan ekspansi tilde, ekspansi parameter dan variabel, substitusi aritmatika, substitusi perintah, dan substitusi proses. Jika opsi shell nocasematch diaktifkan, pertandingan dilakukan tanpa memperhatikan huruf karakter alfabet.

Keduanya Pattern Matchingdan Pathname Expansiondigunakan untuk maksud yang sama di dalam manual bash.

Satu-satunya perbedaan yang dapat saya lihat di manual adalah:

`[[ … ]]`                                   case
tilde  expansion                            tilde expansion
parameter and variable expansion            parameter and variable expansion
arithmetic expansion                        arithmetic substitution
command substitution                        command substitution
process substitution                        process substitution
quote removal

Itu quote removaltidak secara eksplisit tercantum untuk konstruk kasus.
Yang berfungsi persis sama dengan ini (untuk [[ … ]]):

Bagian mana pun dari pola dapat dikutip untuk memaksa agar dicocokkan sebagai string.

Gunakan ini untuk menguji titik terakhir ini (sekarang variabel bukan pola):

case "$1" in
  "$pattern") echo case match
esac

Kenapa hampir?

  1. Tersirat extglob:

    Sejak versi 4.3 dari bash

    Ketika operator '==' dan '! =' Digunakan, string di sebelah kanan operator dianggap sebagai pola dan cocok dengan aturan yang dijelaskan di bawah dalam Pencocokan Pola, seolah-olah opsi shell extglob diaktifkan .

    Itu berarti bahwa pola yang digunakan dengan opsi extglob tidak disetel akan bekerja secara berbeda dalam pernyataan kasus dan di dalam [[konstruk setelah bash versi 4.3.

  2. Tersirat |:

    Sintaks untuk kasus adalah:

    case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

    Yang berarti bahwa mungkin ada beberapa pola yang dipisahkan oleh |(OR).

    Seperti ini:

    shopt -s extglob;      p1="+([0-9])";       p2="+([abcde])"
    
    case "$1" in
        $p1|$p2)    echo "or case match" ; ;;
    esac

    Yang akan cocok dengan string hanya angka atau hanya huruf dalam abcde, suka 1234atau aabee, tetapi tidak 12aatau b23.

    A [[akan bekerja secara setara jika regex (lihat var p3) digunakan:

    #!/bin/bash
    
    shopt -s extglob           ### Use extended globbing.
    shopt -s globasciiranges   ### The range [a-z] will expand to [abcdefghijklmnopqrstuvwxyz].
    
    pattern="+([0-9])"
    p1="+([0-9])"
    p2="+([a-z])"
    p3="^([0-9]+|[a-z]+)$"
    
    case "$1" in
        $pattern)   echo case1 match ; ;&
        $p1|$p2)    echo case2 match ; ;;
    esac
    
    [[ "$1" == $pattern ]] && echo if1 match
    [[ "$1" =~ $p3 ]] && echo if2 match

sumber