Bash'daki tek ve çift tırnaklar arasındaki fark


Yanıtlar:


579

Tek tırnaklar hiçbir şey için enterpolasyon yapmaz, ancak çift tırnak işaretleri olur. Örneğin: değişkenler, ters çentikler, belirli \kaçışlar, vb.

Misal:

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

Bash el kitabı şunları söylemektedir:

3.1.2.2 Tek Alıntılar

Karakterleri tek tırnak içine almak ( ') tırnak içindeki her karakterin gerçek değerini korur. Bir ters eğik çizgiden önce de olsa, tek tırnak işaretleri arasında tek bir tırnak oluşmayabilir.

3.1.2.3 Çift Teklifler

(Çift tırnak karakterleri çevreleyen ") hariç olmak üzere, tırnak içindeki tüm karakterlerin değişmez değerini korur $, `, \, ve, geçmiş genişleme etkinken, !. Karakterler $ve `özel anlamlarını çift tırnak içinde tutun (bkz. Kabuk Genişletmeleri ). Aşağıdaki karakterlerden biri tarafından bitirilen ters eğik çizgi sadece özel bir anlam korur: $, `, ",\veya yeni satır. Çift tırnak içinde, bu karakterlerden birini izleyen ters eğik çizgiler kaldırılır. Özel bir anlamı olmayan karakterlerden önceki ters eğik çizgiler değiştirilmez. Bir çift tırnak, bir ters eğik çizgi ile önüne çift tırnak içine alınabilir. Etkinleştirilirse, !çift ​​tırnak işareti içinde görünen bir ters eğik çizgi kullanılarak çıkış yapılmadığı sürece geçmiş genişlemesi gerçekleştirilir . Tarihinden önceki ters eğik çizgi !kaldırılmaz.

Özel parametreler *ve @çift ​​tırnak içinde özel bir anlamı vardır (bkz. Kabuk Parametre Genişlemesi ).


41
"İnterpolate" in ne anlama geldiğini bilmeyen herkes için: en.wikipedia.org/wiki/String_interpolation
Kolob Kanyonu

Bir git_promptgit kullandığınızda ne olur, bu şekilde kullanmanızı öneririm PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', git istemi , buna göre çalışmamalı. PS#Değişkenler hakkında özel bir şey var mı ? veya enterpolasyon yapmıyorsa neden çalışır?
ekiim

@ekiim Tam metin şu şekilde değiştirildi (değişmedi) PS1. Deneyin echo $PS1ne demek istediğimi görmek için. Ancak PS1görüntülenmeden önce değerlendirilir ( PROMPTINGbash man sayfasındaki bölüme bakın ). Bunu test etmek için deneyin PS1='$X'. Hiç isteminiz olmayacak. Sonra çalıştırın X=foove aniden isteminiz "foo" ( görüntülenen yerine belirlendiğindePS1 değerlendirilmişti hala hiçbir istemi olurdu).
Adam Batkin

262

Kabul edilen cevap harika. Konuyu hızlı bir şekilde anlamaya yardımcı olan bir tablo yapıyorum. Açıklama, basit bir değişkenin ayanı sıra dizinlenmiş bir diziyi de içerir arr.

Eğer ayarlarsak

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

ve sonra echoikinci sütundaki ifadeyi, üçüncü sütunda gösterilen sonucu / davranışı elde ederiz. Dördüncü sütun davranışı açıklar.

 # | 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
---+-------------+-------------+--------------------------------------------------------------------

Ayrıca bakınız:


1
Kabul edilen cevap sonunda diyor The special parameters * and @ have special meaning when in double quotesnasıl oluyor böylece "*"sonuçları *?
anddero

2
@ Karl-AnderoMere, çünkü bu durumda hiç parametre olarak genişletilmemişlerdir. "$@"ve "$*"parametre genişletmeleridir. "@"ve "*"değil.
Charles Duffy

@CharlesDuffy Teşekkürler, şimdi mantıklı!
anddero

3
9 numara, echo "\'"beni döndürür \'.
MaxGyver

@MaxGyver: işaret ettiğiniz için teşekkürler. Cevabı güncelledim.
codeforester

233

Bir şeyi yankıladığınızda ne olacağına atıfta bulunuyorsanız, tek tırnak işaretleri aralarında ne varsa tam anlamıyla yankılanırken, çift tırnaklar arasındaki değişkenleri değerlendirir ve değişkenin değerini verir.

Örneğin, bu

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

bunu verecek:

double quotes gives you sometext
single quotes gives you $MYVAR

11

Diğerleri çok iyi açıkladılar ve basit örneklerle vermek istediler.

Kabuğun herhangi bir özel karakteri yorumlamasını önlemek için metin etrafında tek tırnak kullanılabilir. Dolar işaretleri, boşluklar, ve işaretleri, yıldız işaretleri ve diğer özel karakterler tek tırnak içine alındığında yok sayılır.

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

Bunu verecektir:

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

Tek tırnak içine alınamayan tek şey tek tırnaktır.

Çift tırnaklar tek tırnaklara benzer şekilde hareket eder, ancak çift tırnaklar kabuğun dolar işaretlerini, geri tırnak işaretlerini ve ters eğik çizgileri yorumlamasına izin verir. Ters eğik çizgilerin tek bir özel karakterin yorumlanmasını engellediği zaten bilinmektedir. Bir dolar işareti değişken yerine metin olarak kullanılması gerekiyorsa, bu çift tırnak içinde yararlı olabilir. Ayrıca, tırnak içine alınmış bir dizenin sonu olarak yorumlanmamaları için çift tırnak işaretleri kullanılmasına izin verir.

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

Bunu verecektir:

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

Ayrıca, alıntılanan bir dizenin başlangıcı olarak yorumlanacak olan kesme işaretinin çift tırnak içinde göz ardı edildiği de görülebilir. Bununla birlikte, değişkenler yorumlanır ve çift tırnak içindeki değerleri ile değiştirilir.

$ echo "The current Oracle SID is $ORACLE_SID"

Bunu verecektir:

The current Oracle SID is test

Geri tırnak işaretleri tamamen tek veya çift tırnaklardan farklıdır. Özel tırnakların yorumlanmasını önlemek için kullanılmaktansa, geri alıntılar aslında içerdikleri komutların yürütülmesini zorlar. Ekteki komutlar yürütüldükten sonra, çıktıları orijinal satırdaki arka tırnakların yerine kullanılır. Bu bir örnekle daha açık olacaktır.

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

Bunu verecektir:

Monday, September 28, 2015 

3

Kullanımı arasında net bir ayrım yoktur ' 've " ".

Herhangi bir ' 'şeyin etrafında kullanıldığında, "dönüştürme veya çeviri" yapılmaz. Olduğu gibi yazdırılır.

İle " ", bunu çevreleyen neyse, "tercüme veya dönüştürülmüş" olan değeri içine.

Çeviri / dönüşüm ile kastediyorum: Tek tırnak içindeki hiçbir şey değerlerine "çevrilmeyecek". Onlar tırnak içinde olduğu gibi alınacaktır. Örnek: a=23ardından echo '$a'üretecek $astandart çıktıda. Halbuki standart çıktıda echo "$a"üretilecektir 23.


1
"Çeviri" veya "dönüşüm" ile ne demek istiyorsun?
Nico Haase

Bu cevap oldukça kafa karıştırıcı ve mevcut iyi cevapların üstüne hiçbir şey eklemiyor.
codeforester

2
Bu benim görüşüme göre, anlaşılması benim için kolay olan aşırı bir ifade olmadan kısa bir kısa cevaptı. Çeviri / dönüşüm dendiğinde, çift tırnakların genişleyeceği anlamına gelir; tek tırnakların değişkeni genişletmeyeceği değişken.
B_e_n_n_y_

1
Evet, bu en iyi cevap. Bu kabul edilen cevap olmalı.
Jamey Kirby

3

Bu alıntılarla uğraşırken fiili cevap olduğundan bash, kabuktaki aritmetik operatörlerle uğraşırken yukarıdaki cevaplarda kaçırılan bir noktayı daha ekleyeceğim.

bashKabuk iki yolu aritmetik işlem yapmak destekler ile tanımlanan bir dahili letkomuta ve $((..))operatör. Birincisi aritmetik bir ifadeyi değerlendirirken ikincisi daha çok bileşik bir ifadedir.

Diğer aritmetik letkomutlarda olduğu gibi, kullanılan aritmetik ifadenin sözcük bölme, yol adı genişletme işleminden geçtiğini anlamak önemlidir . Bu yüzden uygun alıntı ve kaçış yapılması gerekiyor.

Kullanırken bu örneğe bakın let

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

Burada tek tırnak işareti kullanmak kesinlikle iyidir, çünkü burada değişken genişletmelere gerek yoktur,

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

olarak, sefil başarısız olur $bartek tırnak altında olacağını değil genişletmek ve ihtiyaçları gibi çift tırnaklı edilecek

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

Bu nedenlerden biri $((..))olmalı, her zaman kullanımı düşünülmelidir let. Çünkü onun içindekiler, kelime bölünmesine tabi değildir. Önceki örnek letkullanımı basitçe şu şekilde yazılabilir:

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

Her zaman $((..))tek tırnak işareti olmadan kullanmayı unutmayın

Gerçi $((..))çift tırnak kullanılabilir, bunun sonucu olarak kendisine amaç yoktur olamaz çift tırnak gereken bir içeriğe sahip. Sadece tek tırnaklı olmadığından emin olun.

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

Bazı özel durumlarda $((..))operatörü tek tırnaklı bir dize içinde kullanmak, tırnak işaretleri operatörünü tırnaksız veya çift tırnak altında bırakacak şekilde enterpolasyon yapmanız gerekir. Örneğin, curlher istek yapıldığında bir sayacı geçmek için bir ifadenin içindeki operatörü kullanmak istediğinizde ,

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

İçinde çift yönlü dizenin alana $((reqcnt++))geçirildiği iç içe çift tırnak işareti kullanıldığına dikkat edin requestCounter.


2
Charles Duffy iyi durumda yapar burada çifte alıntı için $((...))de. "Biraz" paranoyak olabilir ve IFS=0örneğin olması pek olası değildir , ama kesinlikle imkansız değildir :)
Pesa

Bir de eski $[[...]]sözdizimi var ama belki de unutmakta haklıydınız.
tripleee
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.