Perbedaan antara tanda kutip tunggal dan ganda dalam Bash

Jawaban:

580

Kutipan tunggal tidak akan menginterpolasi apa pun, tetapi tanda kutip ganda akan. Sebagai contoh: variabel, backticks, \escapes tertentu , dll.

Contoh:

$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")

Manual Bash mengatakan ini:

3.1.2.2 Kutipan Tunggal

Menutup karakter dalam tanda kutip tunggal ( ') mempertahankan nilai literal setiap karakter dalam tanda kutip. Kutipan tunggal mungkin tidak terjadi di antara tanda kutip tunggal, bahkan ketika didahului oleh garis miring terbalik.

3.1.2.3 Kutipan Ganda

Melampirkan karakter dalam tanda kutip ganda ( ") mempertahankan nilai literal dari semua karakter dalam tanda kutip, dengan pengecualian $, `, \, dan, ketika ekspansi sejarah diaktifkan, !. Karakter $dan `mempertahankan makna khusus mereka dalam tanda kutip ganda (lihat Shell Expansions ). Backslash mempertahankan arti khusus hanya ketika diikuti oleh salah satu karakter berikut: $, `, ",\, atau baris baru. Dalam tanda kutip ganda, garis miring terbalik yang diikuti oleh salah satu karakter ini dihapus. Garis miring terbalik karakter sebelumnya tanpa makna khusus dibiarkan tidak dimodifikasi. Kutipan ganda dapat dikutip dalam tanda kutip ganda dengan mendahului dengan garis miring terbalik. Jika diaktifkan, ekspansi riwayat akan dilakukan kecuali !kemunculan dalam tanda kutip ganda diloloskan menggunakan backslash. Garis miring terbalik sebelum !tidak dihapus.

Parameter khusus *dan @memiliki arti khusus ketika dalam tanda kutip ganda (lihat Ekspansi Parameter Shell ).

Adam Batkin
sumber
41
Bagi siapa pun yang tidak tahu apa artinya "interpolasi": en.wikipedia.org/wiki/String_interpolation
Kolob Canyon
1
Bagaimana ketika Anda menggunakan git_promptgit asalkan mereka menyarankan menggunakannya seperti ini PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', git prompt , menurut ini seharusnya tidak berfungsi. Apakah ada sesuatu yang istimewa tentang PS#variabel? atau mengapa itu bekerja jika tidak melakukan interpolasi.
ekiim
1
@ekiim Teks yang tepat itu diatur (tidak berubah) menjadi PS1. Coba echo $PS1lihat apa yang saya maksud. Tetapi PS1dievaluasi sebelum ditampilkan (lihat PROMPTINGbagian dalam bash manpage). Untuk mengujinya, coba PS1='$X'. Anda tidak akan memiliki prompt. Kemudian jalankan X=foodan tiba-tiba prompt Anda "foo" (telah PS1dievaluasi saat disetel alih-alih ditampilkan, Anda masih tidak memiliki prompt).
Adam Batkin
263

The jawaban yang diterima besar. Saya membuat tabel yang membantu dalam memahami topik dengan cepat. Penjelasannya melibatkan variabel sederhana adan juga array yang diindeks arr.

Jika kita atur

a=apple      # a simple variable
arr=(apple)  # an indexed array with a single element

dan kemudian echoekspresi di kolom kedua, kita akan mendapatkan hasil / perilaku yang ditunjukkan pada kolom ketiga. Kolom keempat menjelaskan perilaku.

 # | Expression  | Result      | Comments
---+-------------+-------------+--------------------------------------------------------------------
 1 | "$a"        | apple       | variables are expanded inside ""
 2 | '$a'        | $a          | variables are not expanded inside ''
 3 | "'$a'"      | 'apple'     | '' has no special meaning inside ""
 4 | '"$a"'      | "$a"        | "" is treated literally inside ''
 5 | '\''        | **invalid** | can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
 6 | "red$arocks"| red         | $arocks does not expand $a; use ${a}rocks to preserve $a
 7 | "redapple$" | redapple$   | $ followed by no variable name evaluates to $
 8 | '\"'        | \"          | \ has no special meaning inside ''
 9 | "\'"        | \'          | \' is interpreted inside "" but has no significance for '
10 | "\""        | "           | \" is interpreted inside ""
11 | "*"         | *           | glob does not work inside "" or ''
12 | "\t\n"      | \t\n        | \t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13 | "`echo hi`" | hi          | `` and $() are evaluated inside ""
14 | '`echo hi`' | `echo hi`   | `` and $() are not evaluated inside ''
15 | '${arr[0]}' | ${arr[0]}   | array access not possible inside ''
16 | "${arr[0]}" | apple       | array access works inside ""
17 | $'$a\''     | $a'         | single quotes can be escaped inside ANSI-C quoting
18 | "$'\t'"     | $'\t'       | ANSI-C quoting is not interpreted inside ""
19 | '!cmd'      | !cmd        | history expansion character '!' is ignored inside ''
20 | "!cmd"      | cmd args    | expands to the most recent command matching "cmd"
21 | $'!cmd'     | !cmd        | history expansion character '!' is ignored inside ANSI-C quotes
---+-------------+-------------+--------------------------------------------------------------------

Lihat juga:

codeforester
sumber
1
Jawaban yang diterima mengatakan pada akhirnya The special parameters * and @ have special meaning when in double quotesjadi bagaimana "*"hasilnya *?
anddero
2
@ Karl-AnderoMere, karena mereka tidak diperluas sebagai parameter dalam kasus itu sama sekali. "$@"dan "$*"merupakan ekspansi parameter. "@"dan "*"tidak.
Charles Duffy
@CharlesDuffy Terima kasih, itu masuk akal sekarang!
anddero
3
Nomor 9 echo "\'",, mengembalikan saya \'.
MaxGyver
@ Maxgyver: terima kasih telah menunjukkannya. Saya telah memperbarui jawabannya.
codeforester
233

Jika Anda merujuk pada apa yang terjadi ketika Anda menggemakan sesuatu, tanda kutip tunggal akan benar-benar menggemakan apa yang Anda miliki di antara mereka, sedangkan tanda kutip ganda akan mengevaluasi variabel di antara mereka dan menghasilkan nilai variabel.

Sebagai contoh, ini

#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'

akan memberikan ini:

double quotes gives you sometext
single quotes gives you $MYVAR
juga
sumber
11

Yang lain menjelaskan dengan sangat baik dan hanya ingin memberi dengan contoh sederhana.

Kutipan tunggal dapat digunakan di sekitar teks untuk mencegah shell menafsirkan karakter khusus. Tanda-tanda dolar, spasi, tanda bintang, tanda bintang, dan karakter khusus lainnya diabaikan ketika dimasukkan dalam tanda kutip tunggal.

$ echo 'All sorts of things are ignored in single quotes, like $ & * ; |.' 

Ini akan memberikan ini:

All sorts of things are ignored in single quotes, like $ & * ; |.

Satu-satunya hal yang tidak dapat dimasukkan ke dalam kutipan tunggal adalah kutipan tunggal.

Kutipan ganda bertindak mirip dengan tanda kutip tunggal, kecuali tanda kutip ganda masih memungkinkan shell untuk menafsirkan tanda dolar, tanda kutip kembali dan garis miring terbalik. Sudah diketahui bahwa backslash mencegah satu karakter khusus dari ditafsirkan. Ini bisa berguna dalam tanda kutip ganda jika tanda dolar perlu digunakan sebagai teks, bukan untuk variabel. Ini juga memungkinkan tanda kutip ganda untuk diloloskan sehingga mereka tidak ditafsirkan sebagai akhir dari string yang dikutip.

$ echo "Here's how we can use single ' and double \" quotes within double quotes"

Ini akan memberikan ini:

Here's how we can use single ' and double " quotes within double quotes

Dapat juga diperhatikan bahwa apostrof, yang jika tidak akan ditafsirkan sebagai awal dari string yang dikutip, diabaikan dalam tanda kutip ganda. Namun, variabel ditafsirkan dan diganti dengan nilainya dalam tanda kutip ganda.

$ echo "The current Oracle SID is $ORACLE_SID"

Ini akan memberikan ini:

The current Oracle SID is test

Kutipan kembali sepenuhnya tidak seperti kutipan tunggal atau ganda. Alih-alih digunakan untuk mencegah penafsiran karakter khusus, kutipan balik justru memaksa pelaksanaan perintah yang mereka lampirkan. Setelah perintah terlampir dijalankan, outputnya diganti dengan tanda kutip di baris aslinya. Ini akan lebih jelas dengan sebuah contoh.

$ today=`date '+%A, %B %d, %Y'`
$ echo $today 

Ini akan memberikan ini:

Monday, September 28, 2015 
Sree
sumber
3

Ada perbedaan yang jelas antara penggunaan ' 'dan " ".

Ketika ' 'digunakan di sekitar apa pun, tidak ada "transformasi atau terjemahan" yang dilakukan. Dicetak seperti apa adanya.

Dengan " ", apa pun yang ada di sekitarnya, "diterjemahkan atau diubah" menjadi nilainya.

Yang saya maksudkan dengan terjemahan / transformasi adalah sebagai berikut: Apa pun di dalam tanda kutip tunggal tidak akan "diterjemahkan" ke nilai-nilai mereka. Mereka akan diambil karena mereka berada di dalam kutipan. Contoh:, a=23maka echo '$a'akan menghasilkan $aoutput standar. Sedangkan echo "$a"akan menghasilkan 23pada output standar.

a_r
sumber
1
Apa yang Anda maksud dengan "terjemahan" atau "transformasi"?
Nico Haase
Jawaban ini cukup membingungkan dan tidak menambahkan apa pun di atas jawaban baik yang ada.
codeforester
2
Ini adalah jawaban singkat dan ringkas menurut saya tanpa terlalu bertele-tele yang mudah untuk saya pahami. Ketika mengatakan terjemahan / transformasi, itu artinya tanda kutip ganda akan memperluas variabel di mana kutip tunggal tidak akan memperluas variabel.
B_e_n_n_y_
1
Ya, ini jawaban terbaik. Ini harus menjadi jawaban yang diterima.
Jamey Kirby
3

Karena ini adalah jawaban de facto ketika berhadapan dengan tanda kutip bash, saya akan menambahkan satu poin lagi yang terlewatkan dalam jawaban di atas, ketika berhadapan dengan operator aritmatika di shell.

The bashshell mendukung dua cara melakukan operasi aritmatika, yang didefinisikan oleh built-in letperintah dan $((..))operator. Yang pertama mengevaluasi ekspresi aritmatika sedangkan yang terakhir lebih merupakan pernyataan majemuk.

Penting untuk memahami bahwa ekspresi aritmatika yang digunakan dengan letmengalami pemekaran kata, perluasan pathname sama seperti perintah shell lainnya. Jadi mengutip dan melarikan diri yang tepat perlu dilakukan.

Lihat contoh ini saat menggunakan let

let 'foo = 2 + 1'
echo $foo
3

Menggunakan tanda kutip tunggal di sini benar-benar baik-baik saja di sini, karena tidak perlu untuk ekspansi variabel di sini, pertimbangkan kasus

bar=1
let 'foo = $bar + 1'

akan gagal total, karena $barkutipan tunggal di bawah tidak akan berkembang dan perlu dikutip ganda sebagai

let 'foo = '"$bar"' + 1'

Ini harus menjadi salah satu alasan, yang $((..))harus selalu dipertimbangkan untuk digunakan let. Karena di dalamnya, konten tidak tunduk pada pemisahan kata. Contoh sebelumnya menggunakan letdapat ditulis sebagai

(( bar=1, foo = bar + 1 ))

Selalu ingat untuk menggunakan $((..))tanpa tanda kutip tunggal

Meskipun $((..))dapat digunakan dengan tanda kutip ganda, tidak ada tujuan untuk itu karena tidak dapat berisi konten yang akan membutuhkan tanda kutip ganda. Pastikan saja tidak dikutip satu pun.

printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2

Mungkin dalam beberapa kasus khusus menggunakan $((..))operator di dalam string yang dikutip tunggal, Anda perlu menginterpolasi tanda kutip sedemikian rupa sehingga operator dibiarkan tanpa tanda kutip atau di bawah tanda kutip ganda. Misalnya mempertimbangkan suatu kasus, ketika Anda ingin menggunakan operator di dalam curlpernyataan untuk melewati konter setiap kali permintaan dibuat, lakukan

curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'

Perhatikan penggunaan tanda kutip ganda bersarang di dalam, yang tanpanya string literal $((reqcnt++))diteruskan ke requestCounterbidang.

Inian
sumber
2
Charles Duffy membuat kasus yang bagus di sini untuk mengutip ganda $((...))juga. Mungkin paranoid "sedikit" dan sangat tidak mungkin IFS=0untuk misalnya, tetapi tentu saja itu tidak mustahil :)
PesaThe
Ada juga $[[...]]sintaks yang lama tetapi mungkin Anda benar melupakannya.
tripleee