$ Teklif etmenin doğru yolu nedir ($ arg komutu)?


17

Beni yıllardır rahatsız eden bu bilmeceyi çözmenin tam zamanı ...

Bunu zaman zaman tanıştım ve bunun bir yol olduğunu düşündüm:

$(comm "$(arg)")

Ve görüşümün deneyim tarafından güçlü bir şekilde desteklendiğini düşündüm. Ama artık o kadar emin değilim. Shellcheck de kararını veremez. Her ikiside:

"$(dirname $0)"/stop.bash
           ^-- SC2086: Double quote to prevent globbing and word splitting.

Ve:

$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.

Arkasındaki mantık nedir?

(Shellcheck 0.4.4 sürümü, btw.)


1
Tüm oyuncu değişikliklerini teklif et.
Ignacio Vazquez-Abrams

3
Sadece böyle: "$(dirname "$0")"/stop.bash? İşe yarıyor gibi ... Hikaye ne?

1
bash, bağlamın ne zaman değiştiğini bilecek kadar akıllıdır.
Ignacio Vazquez-Abrams

1
şöyle düşünün: shell_level_1 $(shell_level_2) shell_level_1İçinde olduğunuzda, $(....)bir "alt seviye" kabuk girin, AMA ilköğretim seviyesindeymiş gibi yazabilirsiniz (yani, doğrudan "yerine yazabilirsiniz \", vb.). örnek: touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to \ "/ tmp / bir dosya \" `bulun ve print \$5. Gerek $(...)yok: kabuk yeni seviyeye adapte olur ve doğrudan tercümanınız da bu seviyedeymiş gibi yazabilirsiniz.
Olivier Dulac

"Shellcheck de kararını veremez." - İki koşunun iki farklı mesajı vardır ve farklı yerleri işaret ederler. Her ikisini de istiyor.
Izkata

Yanıtlar:


45

Kullanmalısın "$(somecmd "$file")" .

Tırnak işaretleri olmadan, boşluk içeren bir yol, somecmd ve yanlış dosyayı hedefler. Yani içeride alıntılara ihtiyacınız var.

Çıktısında herhangi bir boşluk somecmd da bölünmeye neden olur, bu nedenle tüm komut ikamesinin dışında tırnaklara ihtiyacınız vardır.

Komut ikamesi içindeki tırnak işaretleri, tırnak dışındaki tırnaklar üzerinde hiçbir etkiye sahip değildir. Bash'in kendi referans kılavuzu bu konuda çok açık değil, ancak BashGuide bundan açıkça bahsediyor . POSIX içindeki metin, içinde "geçerli herhangi bir kabuk komut dosyasına" izin verildiği için de bunu gerektirir $(...):

İle $(command)forma, eşleştirme kapanış parantez açık parantez aşağıdaki tüm karakterler komutunu oluşturmaktadır. Yalnızca belirtilmemiş sonuçlar üreten yeniden yönlendirmelerden oluşan bir komut dosyası dışında, komut için geçerli herhangi bir kabuk komut dosyası kullanılabilir.


Misal:

$ file="./space here/foo"

a. Hiçbir tırnak, dirnamehem işler ./spaceve here/foo:

$ printf "<%s>\n" $(dirname $file)
<.>
<here>

b. İçinden alıntılar, dirnamesüreçler ./space here/foo, veren ./space here, ikiye bölünmüş:

$ printf "<%s>\n" $(dirname "$file")
<./space>
<here>

c. Dışarıdan alıntılar, dirnameher ikisini de işler ./spaceve here/fooayrı satırlardaki çıktılar, ancak şimdi iki satır tek bir argüman oluşturur :

$ printf "<%s>\n" "$(dirname $file)"
<.
here>

d. Hem içeride hem dışarıda alıntılar, bu doğru cevabı verir:

$ printf "<%s>\n" "$(dirname "$file")"
<./space here>

(bu dirnameyalnızca ilk argümanı işleseydi daha basit olurdu , ancak a ve c davaları arasındaki farkı göstermezdi.)

O Not dirname(diğerleri ve muhtemelen) ayrıca eklemek istediğiniz gerek --, bir çizgi ile başlamış olur durumunda bir seçenek olarak alınan kullanım böylece olmaktan dosya adı önlemek için, "$(dirname -- "$file")".


16
Not: Genel olarak, tırnak işaretleri bash içinde yuvalanmaz; ancak bu durumda, $( )yeni bir bağlam yaratır, böylece içindeki tırnaklar onun dışındaki tırnaklardan bağımsızdır. Ve genellikle her iki bağlamda da alıntılar istiyorsunuz.
Gordon Davisson
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.