GNU/Linux >> Belajar Linux >  >> Linux

Kapan Mengutip Ganda Diperlukan?

Saran lama dulu adalah mengutip dua kali ekspresi apa pun yang melibatkan $VARIABLE , setidaknya jika seseorang ingin itu ditafsirkan oleh Shell sebagai satu item tunggal, jika tidak, spasi apa pun dalam konten $VARIABLE akan membuang cangkangnya.

Saya mengerti, bagaimanapun, bahwa dalam versi shell yang lebih baru, kutipan ganda tidak lagi selalu diperlukan (setidaknya untuk tujuan yang dijelaskan di atas). Misalnya, di bash :

% FOO='bar baz'
% [ $FOO = 'bar baz' ] && echo OK
bash: [: too many arguments
% [[ $FOO = 'bar baz' ]] && echo OK
OK
% touch 'bar baz'
% ls $FOO
ls: cannot access bar: No such file or directory
ls: cannot access baz: No such file or directory

Dalam zsh , di sisi lain, tiga perintah yang sama berhasil. Oleh karena itu, berdasarkan percobaan ini, tampaknya, dalam bash , seseorang dapat menghilangkan tanda kutip ganda di dalam [[ ... ]] , tetapi tidak di dalam [ ... ] maupun dalam argumen baris perintah, sedangkan, dalam zsh , tanda kutip ganda dapat dihilangkan dalam semua kasus ini.

Tapi menyimpulkan aturan umum dari contoh anekdot seperti di atas adalah proposisi kebetulan. Akan menyenangkan untuk melihat ringkasan kapan kutipan ganda diperlukan. Saya terutama tertarik pada zsh , bash , dan /bin/sh .

Jawaban yang Diterima:

Pertama, pisahkan zsh dari yang lain. Ini bukan masalah shell lama vs shell modern:zsh berperilaku berbeda. Desainer zsh memutuskan untuk membuatnya tidak kompatibel dengan shell tradisional (Bourne, ksh, bash), tetapi lebih mudah digunakan.

Kedua, jauh lebih mudah menggunakan tanda kutip ganda setiap saat daripada mengingat saat dibutuhkan. Mereka paling sering dibutuhkan, jadi Anda perlu belajar saat tidak dibutuhkan, bukan saat dibutuhkan.

Singkatnya, tanda kutip ganda diperlukan di mana pun daftar kata atau pola diharapkan . Mereka opsional dalam konteks di mana string mentah diharapkan oleh pengurai.

Apa yang terjadi tanpa tanda kutip

Perhatikan bahwa tanpa tanda kutip ganda, dua hal terjadi.

  1. Pertama, hasil ekspansi (nilai variabel untuk substitusi parameter seperti ${foo} , atau output dari perintah untuk substitusi perintah seperti $(foo) ) dipecah menjadi kata-kata di mana pun mengandung spasi.
    Lebih tepatnya, hasil perluasan dibagi pada setiap karakter yang muncul dalam nilai IFS variabel (karakter pemisah). Jika urutan karakter pemisah berisi spasi (spasi, tab, atau baris baru), spasi putih dihitung sebagai satu karakter; pemisah non-spasi awal, akhir, atau berulang mengarah ke bidang kosong. Misalnya, dengan IFS=" :" , :one::two : three: :four  menghasilkan bidang kosong sebelum one , antara one dan two , dan (satu satu) di antara three dan four .
  2. Setiap bidang yang dihasilkan dari pemisahan ditafsirkan sebagai glob (pola wildcard) jika berisi salah satu karakter [*? . Jika pola tersebut cocok dengan satu atau beberapa nama file, pola tersebut akan diganti dengan daftar nama file yang cocok.

Ekspansi variabel yang tidak dikutip $foo bahasa sehari-hari dikenal sebagai “operator split+glob”, berbeda dengan "$foo" yang hanya mengambil nilai dari variabel foo . Hal yang sama berlaku untuk substitusi perintah:"$(foo)" adalah substitusi perintah, $(foo) adalah substitusi perintah diikuti oleh split+glob.

Di mana Anda dapat menghilangkan tanda kutip ganda

Berikut adalah semua kasus yang dapat saya pikirkan dalam shell gaya Bourne di mana Anda dapat menulis variabel atau substitusi perintah tanpa tanda kutip ganda, dan nilainya ditafsirkan secara harfiah.

  • Di sisi kanan tugas.

    var=$stuff
    a_single_star=*
    

    Perhatikan bahwa Anda memerlukan tanda kutip ganda setelah export , karena ini adalah bawaan biasa, bukan kata kunci. Ini hanya berlaku di beberapa shell seperti dash, zsh (dalam emulasi sh), yash atau posh; bash dan ksh keduanya memperlakukan export khusus.

    export VAR="$stuff"
    
  • Dalam case pernyataan.

    case $var in …
    

    Perhatikan bahwa Anda membutuhkan tanda kutip ganda dalam pola kasus. Pemisahan kata tidak terjadi dalam pola kasus, tetapi variabel yang tidak dikutip diinterpretasikan sebagai pola sedangkan variabel yang dikutip ditafsirkan sebagai string literal.

    a_star='a*'
    case $var in
      "$a_star") echo "'$var' is the two characters a, *";;
       $a_star) echo "'$var' begins with a";;
    esac
    
  • Dalam tanda kurung ganda. Tanda kurung ganda adalah sintaksis khusus shell.

    [[ -e $filename ]]
    

    Kecuali bahwa Anda memang memerlukan tanda kutip ganda di mana pola atau ekspresi reguler diharapkan:di sisi kanan = atau == atau != atau =~ .

    a_star='a*'
    if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
    elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
    fi
    

    Anda perlu tanda kutip ganda seperti biasa dalam tanda kurung tunggal [ … ] karena mereka adalah sintaksis shell biasa (ini adalah perintah yang kebetulan disebut [ ). Lihat Tanda kurung tunggal atau ganda

  • Dalam pengalihan di shell POSIX non-interaktif (bukan bash , atau ksh88 ).

    echo "hello world" >$filename
    

    Beberapa shell, ketika interaktif, memperlakukan nilai variabel sebagai pola wildcard. POSIX melarang perilaku itu di shell non-interaktif, tetapi beberapa shell termasuk bash (kecuali dalam mode POSIX) dan ksh88 (termasuk ketika ditemukan sebagai (seharusnya) POSIX sh dari beberapa Unix komersial seperti Solaris) masih melakukannya di sana (bash juga mencoba memecah dan pengalihan gagal kecuali split+globbing menghasilkan tepat satu kata), itulah sebabnya lebih baik mengutip target pengalihan dalam sh skrip jika Anda ingin mengubahnya menjadi bash skrip suatu hari nanti, atau jalankan di sistem di mana sh tidak patuh pada saat itu, atau mungkin bersumber dari cangkang interaktif.

  • Di dalam ekspresi aritmatika. Bahkan, Anda harus meninggalkan tanda kutip agar variabel dapat diuraikan sebagai ekspresi aritmatika.

    expr=2*2
    echo "$(($expr))"
    

    Namun, Anda memerlukan tanda kutip di sekitar ekspansi aritmatika karena mereka tunduk pada pemisahan kata di sebagian besar shell seperti yang dibutuhkan POSIX (!?).

  • Dalam subskrip larik asosiatif.

    typeset -A a
    i='foo bar*qux'
    a[foo bar*qux]=hello
    echo "${a[$i]}"
    

Variabel yang tidak dikutip dan substitusi perintah dapat berguna dalam beberapa keadaan yang jarang terjadi:

  • Bila nilai variabel atau keluaran perintah terdiri dari daftar pola glob dan Anda ingin memperluas pola ini ke daftar file yang cocok.
  • Bila Anda mengetahui bahwa nilainya tidak mengandung karakter wildcard, $IFS itu tidak diubah dan Anda ingin membaginya menjadi karakter spasi.
  • Bila Anda ingin membagi nilai pada karakter tertentu:nonaktifkan globbing dengan set -f , atur IFS ke karakter pemisah (atau biarkan terpisah di spasi), lalu lakukan ekspansi.
Terkait:Mengapa menggunakan swap ketika ada lebih dari cukup ruang kosong di RAM?

Zsh

Di zsh, Anda sering kali dapat menghilangkan tanda kutip ganda, dengan beberapa pengecualian.

  • $var tidak pernah diperluas ke beberapa kata, namun diperluas ke daftar kosong (sebagai lawan dari daftar yang berisi satu kata kosong) jika nilai var adalah string kosong. Kontras:

    var=
    print -l $var foo        # prints just foo
    print -l "$var" foo      # prints an empty line, then foo
    

    Demikian pula, "${array[@]}" memperluas ke semua elemen array, sementara $array hanya meluas ke elemen yang tidak kosong.

  • @ bendera ekspansi parameter terkadang memerlukan tanda kutip ganda di sekitar seluruh substitusi:"${(@)foo}" .

  • Substitusi perintah mengalami pemisahan bidang jika tidak dikutip:echo $(echo 'a'; echo '*') mencetak a * (dengan spasi tunggal) sedangkan echo "$(echo 'a'; echo '*')" mencetak string dua baris yang tidak dimodifikasi. Gunakan "$(somecommand)" untuk mendapatkan output dari perintah dalam satu kata, tanpa baris baru terakhir. Gunakan "${$(somecommand; echo _)%?}" untuk mendapatkan output yang tepat dari perintah termasuk baris baru terakhir. Gunakan "${(@f)$(somecommand)}" untuk mendapatkan larik baris dari output perintah.

Terkait:mengeset -A memberikan kesalahan dalam skrip?
Linux
  1. Bagaimana Cara Menghindari Kutipan Di Shell?

  2. Apa Mnemonic yang Baik Untuk Shell Double Vs. Kutipan Tunggal?

  3. Bagaimana Cara Menambahkan Baris Baru Ke Variabel Dalam Skrip Bash?

  1. Mengapa Garis Miring Balik Tunggal Ditampilkan Saat Menggunakan Kutipan?

  2. Kapan harus menggunakan Server Khusus

  3. Kapan harus membungkus tanda kutip di sekitar variabel shell?

  1. Saat mengatur IFS untuk dibagi pada baris baru, mengapa perlu menyertakan backspace?

  2. perintah bash alias dengan tanda kutip tunggal dan ganda

  3. Kapan diperlukan reboot?