Apa perbedaan antara kutipan “...”, '...', $ '...', dan $ “...”?

49

Kadang-kadang saya melihat script menggunakan semua cara-cara yang berbeda mengutip beberapa teks: "...", '...', $'...', dan $"...". Mengapa ada begitu banyak jenis kutipan yang digunakan?

Apakah mereka berperilaku berbeda atau memengaruhi apa yang dapat saya lakukan di dalamnya?

Michael Homer
sumber
1
Kemungkinan duplikat lintas-situs. Jawaban ini memberikan ringkasan (atau tautan ke) semantik dari semua jenis kutipan yang berbeda.
chepner

Jawaban:

66

Semua ini berarti sesuatu yang berbeda, dan Anda dapat menulis hal-hal yang berbeda di dalamnya (atau hal yang sama, dengan makna berbeda). Berbagai jenis kutipan menafsirkan urutan pelarian yang berbeda di dalamnya ( \something), atau melakukan atau tidak mengizinkan interpolasi variabel ( $something) dan jenis ekspansi lainnya di dalamnya.

Pendeknya:

  • '...' sepenuhnya literal.
  • "..." memungkinkan kedua variabel dan karakter kutipan yang disematkan.
  • $'...'melakukan pelarian karakter seperti \n, tetapi tidak memperluas variabel.
  • $"..." adalah untuk terjemahan bahasa manusia dalam Bash dan ksh.

'Kutipan tunggal'

Apa pun yang Anda tulis di antara tanda kutip tunggal diperlakukan secara harfiah dan tidak diproses sama sekali. Tanda garis miring terbalik dan tanda dolar tidak memiliki arti khusus di sana. Ini berarti Anda tidak dapat melepaskan diri dari karakter (termasuk tanda kutip tunggal lainnya!), Menginterpolasi variabel, atau menggunakan fitur shell lainnya.

Semua contoh ini menghasilkan apa yang tertulis di antara kutipan:

'hello world'                     => hello world
'/pkg/bin:$PATH'                  => /pkg/bin:$PATH
'hello\nworld'                    => hello\nworld
'`echo abc`'                      => `echo abc`
'I\'dn\'t've'                     => I\dn'tve

Yang terakhir rumit - ada dua string yang dikutip tunggal dijalankan bersama dengan beberapa teks yang tidak dikutip. Yang pertama berisi I\. Teks yang tidak dn\'tdikutip mengandung satu kutipan yang lolos pada level shell , sehingga tidak memulai string yang dikutip dan dimasukkan sebagai karakter literal (jadi, dn't). String terakhir yang dikutip adalah adil ve. Semua itu dijalankan bersama menjadi satu kata dengan cara yang biasa shell bekerja.

Idiom yang agak umum untuk menggabungkan teks dan variabel literal adalah menjalankannya bersama seperti itu:

'let x="'$PATH\"

akan menghasilkan

let x="/usr/bin:/bin"

sebagai satu kata (yang lebih baik untuk double-quote $PATHjuga hanya dalam kasus - spasi atau globbing karakter dalam variabel nilai dapat diproses sebaliknya - tapi demi contoh berjalan dibaca saya belum).


"Kutipan ganda"

Di dalam tanda kutip ganda, dua jenis ekspansi diproses, dan Anda dapat menggunakan garis miring terbalik untuk menghindari karakter untuk mencegah ekspansi atau lolos dari diproses.

Ada dua kategori ekspansi yang terjadi di dalam tanda kutip ganda:

Di dalam tanda kutip, garis miring terbalik dapat menghambat mereka ekspansi dengan menempatkan sebelum $atau `. Itu juga dapat menghindari kutip ganda penutupan, jadi \"termasuk saja "dalam string Anda, atau backslash lainnya. Setiap backslash lainnya dipertahankan secara literal - tidak ada jalan keluar untuk menghasilkan karakter lain, dan itu tidak dihapus.

Beberapa contoh ini bertindak berbeda dari sebelumnya, dan beberapa tidak:

"hello world"                     => hello world
"/pkg/bin:$PATH"                  => /pkg/bin:/bin:/usr/bin
"hello\nworld"                    => hello\nworld
"hello\\nworld"                   => hello\nworld
"`echo abc`"                      => abc
"I\'dn\'t've"                     => I\'dn\'t've
"I'dn't've"                       => I'dn't've
"I\"dn\"t've"                     => I"dn"t've

$ 'Kutipan ANSI-C'

Jenis kutipan ini memungkinkan backslash C-style untuk diproses, tetapi bukan variabel atau substitusi yang disematkan. Ini satu - satunya jenis kutipan yang mendukung pelarian karakter .

Ini adalah ekstensi dari ksh, sekarang didukung di Bash, zsh, dan beberapa shell lainnya juga. Ini belum menjadi bagian dari standar POSIX dan skrip portabel yang maksimal tidak dapat menggunakannya, tetapi skrip Bash atau ksh bebas untuk menggunakannya.

Semua lolos ini dapat digunakan dengan arti C mereka: \a, \b, \f, \n, \r, \t, \v, dan lolos literal \\, \', \", dan \?. Mereka juga mendukung ekstensi \e(karakter escape) dan dalam Bash dan ksh \cx(apa yang akan dimasukkan oleh Ctrl-x , misalnya \cMcarriage return). Shell memiliki serangkaian ekstensi kecil sendiri.

Ini juga memungkinkan empat jenis karakter generik lolos:

  • \nnn, satu byte dengan nilai oktal nnn
  • \xHH, satu byte dengan nilai heksadesimal HH
  • \uHHHH, titik kode Unicode yang indeks heksadesimalnya adalah HHHH
  • \UHHHHHHHH, titik kode Unicode yang indeks heksadesimalnya adalah HHHHHHHH

Semua digit itu adalah opsional setelah yang pertama.

$dan `tidak memiliki makna dan dipertahankan secara harfiah, sehingga Anda tidak dapat memasukkan variabel di sana.

$'hello world'                    => hello world
$'/pkg/bin:$PATH'                 => /pkg/bin:$PATH
$'hello\nworld'                   => hello
                                     world
$'`echo abc`'                     => `echo abc`
$'I\'dn\'t\'ve'                   => I'dn't've
$'\U1f574\u263A'                  => 🕴☺

Sebagian besar lolos ini Anda dapat mensimulasikan menggunakan satu printfperintah , meskipun POSIX hanya membutuhkan \\, \a, \b, \f, \n, \r, \t, \v, dan \nnnuntuk bekerja di sana. Anda dapat menggunakan substitusi perintah untuk menanamkan printftanda kutip ganda dalam jika diperlukan: "Path:$(printf '\t')$PATH".


$ "Terjemahan lokal"

Ini adalah ekstensi spesifik ksh dan Bash untuk string tekstual bahasa alami yang melokalisasi, dan mencari bagian di dalam tanda kutip dalam katalog pesan. Ia melakukan semua ekspansi kuotasi ganda terlebih dahulu. Jika string tidak ditemukan dalam database terjemahan, itu digunakan sebagai terjemahannya sendiri. Asumsi bawaan adalah bahwa string adalah dalam bahasa Inggris.

Anda mungkin tidak ingin menggunakan yang ini, tetapi jika Anda melihatnya, Anda biasanya dapat memperlakukannya sebagai tanda kutip ganda biasa.


Satu hal yang perlu diperhatikan adalah tidak ada jenis kutipan yang memungkinkan perluasan parameter tertanam dan karakter tertanam lolos. Dalam kebanyakan kasus di mana Anda menginginkannya, Anda akan lebih baik (lebih aman) menggunakan printf:

printf 'New path: \e[1m%s\e[0m' "/pkg/bin:$PATH:"

Ini dengan jelas memisahkan bagian mana yang dapat lolos dari karakter dan mana yang merupakan nilai data.

Lain adalah bahwa semua gaya mengutip membuat satu "kata" di shell, kecuali $@ atau ekspansi array ${x[@]}digunakan di dalam tanda kutip ganda. Kedua bentuk kutipan tunggal selalu satu kata dan tidak pernah berkembang lebih jauh.

Michael Homer
sumber
$"..."juga dari ksh93, ditambahkan ke bash di 2.0.
Stéphane Chazelas
Tidak ada \cXdi zsh. Itu \CXatau di \C-Xsana ( \csudah memiliki arti khusus echo)
Stéphane Chazelas
'let x="'$PATH\"salah dalam konteks daftar di shell selain zshseperti $PATHyang tidak dikutip (jadi akan dikenakan split + glob yang tidak Anda inginkan di sini).
Stéphane Chazelas
Anda mungkin ingin mengklarifikasi bahwa Anda berbicara tentang cangkang mirip Korn, pemrosesan kutipan berbeda dalam csh, rc, fish ...
Stéphane Chazelas
@ StéphaneChazelas Tentukan "konteks daftar".
Isaac