Bash komutundaki değişkenlerin tek tırnak içinde genişletilmesi


393

Ben tek tırnak ve tek tırnak ve bir değişken içinde diğer bazı komutları olan bir bash komut dosyası bir komut çalıştırmak istiyorum .

Örneğin repo forall -c '....$variable'

Bu biçimde, çıkış $yapılır ve değişken genişletilmez.

Aşağıdaki varyasyonları denedim ama reddedildiler:

repo forall -c '...."$variable" '

repo forall -c " '....$variable' "

" repo forall -c '....$variable' "

repo forall -c "'" ....$variable "'"

Değişkenin yerine değeri değiştirirsem, komut gayet iyi yürütülür.

Lütfen bana nerede yanlış gittiğimi söyle.


33
repo forall -c ' ...before... '"$variable"' ...after...'
n. 'zamirler' m.

2
@nm tek tırnak işaretleri repo komutunun bir parçasıdır. bunun işe yarayacağını sanmıyorum
Rachit

1
bashtek tırnak yiyor. Ya içinde değilsiniz bashya da tek tırnaklar repokomutun bir parçası değildir .
n. 'zamirler' m.

Seni anladığımdan emin değilim, ancak tek tırnak olması gerektiğinde, -c "'... önce ..." $ değişken "... sonra ...'" repo repo olmaz mı?
ecv

Onun bash kabuğunda çalışan bir bash betiği ve repo forall komutu tek tırnak içinde parametreleri alır. Gerçek değeri değiştirirsem, komut iyi çalışır.
Rachit

Yanıtlar:


621

Tek tırnak içinde her şey istisnasız tam anlamıyla korunur.

Bu, tırnak işaretlerini kapatmanız, bir şeyler eklemeniz ve ardından tekrar girmeniz gerektiği anlamına gelir.

'before'"$variable"'after'
'before'"'"'after'
'before'\''after'

Kelime birleştirme basitçe yan yana getirilerek yapılır. Doğrulayabileceğiniz gibi, yukarıdaki satırların her biri kabuğa tek bir kelimedir. Tırnak işaretleri (duruma bağlı olarak tek veya çift tırnak) kelimeleri ayırmaz. Onlar sadece boşluk gibi, çeşitli özel karakterlerin devre dışı yorumlanması için kullanılır, $, ;... alıntı üzerinde iyi bir eğitim için Mark Reed'in cevaba bakınız. Ayrıca ilgili: Hangi karakterlerin bash'da kaçması gerekir?

Kabuk tarafından yorumlanan dizeleri birleştirmeyin

Değişkenleri birleştirerek kabuk komutları oluşturmaktan kesinlikle kaçınmalısınız. Bu, SQL fragmanlarının birleştirilmesine benzer kötü bir fikirdir (SQL enjeksiyonu!).

Genellikle komutta yer tutucuların bulunması ve komutun değişkenlerle birlikte sağlanması, arayanın onları çağırma bağımsız değişkenleri listesinden alabilmesi için mümkündür.

Örneğin, aşağıdakiler çok güvensizdir. BUNU YAPMAYIN

script="echo \"Argument 1 is: $myvar\""
/bin/sh -c "$script"

İçeriği $myvargüvenilmezse, işte bir istismar:

myvar='foo"; echo "you were hacked'

Yukarıdaki çağrı yerine konumsal argümanlar kullanın. Aşağıdaki çağırma daha iyidir - sömürülebilir değildir:

script='echo "arg 1 is: $1"'
/bin/sh -c "$script" -- "$myvar"

İçin atamada tek kenelerin kullanıldığına dikkat edin script, bu da kelimenin tam anlamıyla değişken genişleme veya başka bir yorumlama biçimi olmadan alındığı anlamına gelir.


@ Jo.SO işe yaramayacak. çünkü repo komutu ilk tırnak işaretleri kapanana kadar sadece parametreleri alacaktır. Bundan sonraki her şey repo için yok sayılır ve başka bir hata oluşturur.
Rachit

8
@Rachit - kabuk böyle çalışmıyor. "some"thing' like'thiskabuğun tek kelimesidir. Tırnak işaretleri ayrıştırma söz konusu olduğunda hiçbir şeyi sonlandırmaz ve kabuk tarafından çağrılan bir komutun neyin nasıl aktarıldığını söylemesinin bir yolu yoktur .
Mark Reed

3
Bu ikinci cümle ("tek tırnaklardan bile kaçamazsınız") tek tırnaklar Kabuğun kara deliklerini yapar.

@Evert: Nasıl daha iyi söyleyeceğimi bilmiyorum. Cümleyi kaldırdım.
Jo So

@JoSo Bu bir utanç: hayır şaka düz düşmez.

96

repoKomut o alır tırnak ne tür umursayamazsınız. Parametre genişletmeye ihtiyacınız varsa, çift tırnak kullanın. Bu, birçok şeyi ters eğmek zorunda kaldığınız anlamına gelirse, çoğu için tek tırnak kullanın ve ardından bunları genişletin ve genişlemenin gerçekleşmesi gereken kısım için iki katına çıkın.

repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff'

İlgileniyorsanız açıklama gelir.

Kabuktan bir komut çalıştırdığınızda, bu komutun bağımsız değişken olarak aldığı şey null sonlu dizelerden oluşan bir dizidir. Bu dizeleri kesinlikle içerebilir herhangi boş olmayan karakter.

Ancak kabuk, komut dizesinden bu dizeleri oluştururken, bazı karakterleri özel olarak yorumlar; bu komutların yazılmasını daha kolay (gerçekten mümkün) yapmak için tasarlanmıştır. Örneğin, boşluklar normalde dizideki dizeler arasındaki sınırı belirtir; bu nedenle, münferit argümanlara bazen "kelimeler" denir. Ancak yine de bir argümanın içinde boşluklar olabilir; sadece mermiye bunu istediğini söylemek için bir yola ihtiyacın var.

Kabuğa bu karakteri tam anlamıyla tedavi etmesini bildirmek için herhangi bir karakterin (boşluk veya başka bir ters eğik çizgi dahil) önünde ters eğik çizgi kullanabilirsiniz. Ama böyle bir şey yapabilirken:

echo \"Thank\ you.\ \ That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

... yorucu olabilir. Kabuk bir alternatif sunar: tırnak işaretleri. Bunlar iki ana çeşittir.

Çift tırnak işaretleri "gruplama tırnakları" olarak adlandırılır. Joker karakterlerin ve takma adların genişletilmesini önlerler, ancak çoğunlukla bir kelimeye boşluk eklemek içindir. Parametre ve komut genişletme (a ile işaret edilen şeyler) gibi diğer şeyler $hala olur. Ve tabii ki çift tırnak içinde gerçek bir çift tırnak istiyorsanız, ters eğik çizgi yapmanız gerekir:

echo "\"Thank you. That'll be \$4.96, please,\" said the cashier"

Tek tırnak işaretleri daha acımasızdır. Aralarındaki her şey, ters eğik çizgiler de dahil olmak üzere tam anlamıyla alınır. Tek tırnak içine gerçek bir tek alıntı almanın kesinlikle bir yolu yoktur.

Neyse ki, kabuktaki tırnak işaretleri sözcük sınırlayıcılar değildir ; kendi başlarına bir kelimeyi sonlandırmazlar. İstediğiniz sonucu elde etmek için aynı sözcük içinde farklı tırnak türleri arasında dahil olmak üzere tırnak içine girip çıkabilirsiniz:

echo '"Thank you. That'\''ll be $4.96, please," said the cashier'

Bu daha kolay - çok daha az ters eğik çizgi, yakın-tek tırnak, ters eğik-gerçek-tek tırnak, açık-tek tırnak dizisi alışmak biraz zaman alıyor.

Modern mermiler, POSIX standardında belirtilmeyen başka bir teklif stili ekledi, burada önde gelen tek tırnak işaretinin önüne dolar işareti eklendi. Bu şekilde alıntılanan dizeler, ANSI C programlama dilinde dizgi değişmezlerine benzer kuralları izler ve bu nedenle bazen "ANSI dizeleri" olarak adlandırılır ve $'... '"ANSI tırnakları" çifti olarak adlandırılır . Bu tür dizelerde, ters eğik çizgilerin tam anlamıyla alınmasına ilişkin yukarıdaki tavsiye artık geçerli değildir. Sadece buna ters eğik çizgi ekleyerek bu bir hazır tek tırnak işareti veya ters eğik çizgi içerebilir, ancak kabuk da benzeri (ANSI C karakter kaçar genişletir - Bunun yerine, yine özel hale \n, bir yeni satır için \tsekme için ve \xHHkarakteri ile için onaltılı kodHH). Aksi halde, tek tırnaklı dizeler gibi davranırlar: parametre veya komut ikamesi gerçekleşmez:

echo $'"Thank you.  That\'ll be $4.96, please," said the cashier'

Dikkat edilmesi gereken önemli nokta, echokomutun argümanı olarak alınan tek dizenin tüm bu örneklerde tamamen aynı olmasıdır . Kabuk bir komut satırını ayrıştırdıktan sonra, komutun çalıştırılmasının neyin nasıl aktarıldığını söylemesinin bir yolu yoktur. İsteseydi bile.


2
Evet. Şimdi anlıyorum. Mükemmel çalışıyor. Yardımın için çok teşekkürler!
Rachit

6
Bu cevap harikaydı.
Vinícius Ferrão

1
$'string'biçimi POSIX uyumlu? Ayrıca, bunun için bir isim var mı?
Joker

2
@Wildcard $'string', "ANSI dizeleri" olarak adlandırılan gördüğüm POSIX olmayan bir uzantıdır ; Bu gerçekleri cevaba dahil ettim. Bu dizeler Bourne uyumlu modern kabukların çoğunda çalışır: bash, dash, ksh (hem AT&T hem de PD) ve zsh bunları destekler.
Mark Reed


3

Benim için işe yarayan şey aşağıdadır -

QUOTE="'"
hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"

2
Umarım TBL_HDFS_DIR_PATH kullanıcı tarafından sağlanan btw girişi değildir, bu güzel bir sql enjeksiyonuna izin verir ...
domenukk

1
QUOTEAyrı bir değişkene koymak tamamen gereksizdir; çift ​​tırnak içindeki tek tırnak sadece normal bir karakterdir. (Ayrıca, özel değişkenleriniz için büyük harf kullanmayın.)
tripleee

2

EDIT: (Söz konusu yorumlara göre :)

O zamandan beri buna bakıyorum. Etrafta repo yaptığım için yeterince şanslıydım. Yine de komutlarınızı zorla tek tırnak arasına almanız gerekip gerekmediği açık değil. Repo sözdizimine baktım ve ihtiyacın olduğunu düşünmüyorum. Komutunuzun etrafında çift tırnak kullanabilirsiniz ve sonra çift tırnaklardan kaçmak şartıyla ihtiyacınız olan tek ve çift tırnakları kullanabilirsiniz.


Yardımınız için teşekkürler Kevin.
Rachit

2

sadece printf kullan

onun yerine

repo forall -c '....$variable'

değişken belirtecini genişletilmiş değişkenle değiştirmek için printf kullanın.

Örneğin:

template='.... %s'

repo forall -c $(printf "${template}" "${variable}")

Bu kırık; printfsize burada gerçekten bir şey satın almaz ve alt birim komutu komutundan alıntı yapmamak yeni teklif sorunlarına neden olur.
Üçlü

0

Değişkenler tek tırnak içerebilir.

myvar=\'....$variable\'

repo forall -c $myvar

Yapabilirler, ancak bu bunu yapmanın doğru yolu değildir - yine "$myvar"de çift tırnak koymalısınız .
Üçlü

-2

Bu senin için uygun mu?

eval repo forall -c '....$variable'

8
Senin için mi? Bu soru beş yaşında ve zaten bazı cevapları var, hatta kabul edilen bir soru ...
Nico Haase
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.