tl; Dr.
Bir tek stuffolurdu muhtemelen senin için çalışıyorum.
Tam cevap
Ne oluyor
Koşarken foo $(stuff), olan bu:
stuff koşar;
- çıktısı (stdout), yazdırılmak yerine
$(stuff), çağrısında bulunur foo;
- sonra
fooçalışır, komut satırı argümanları açıkça stuffgeri dönenlere bağlıdır .
Bu $(…)mekanizmaya "komut değiştirme" denir. Senin durumunda ana komut, echotemelde komut satırı argümanlarını stdout'a basan komuttur. Bu yüzden stuffstdout'a yazdırmaya çalışanlar yakalanır, iletilir echove stdout'a yazdırılır echo.
stuffÇıktısının stdout'a yazdırılmasını istiyorsanız , yalnızca tabanı çalıştırın stuff.
`…`Sözdizimi ile aynı amaca hizmet eder $(…)(aynı adla: "komutu ikamesi") körü körüne onları birbirleriyle karıştırmayın böylece olsa birkaç farklılık vardır. Bkz bu SSS ve bu soruyu .
Ne echo $(stuff)olursa olsun kaçınmalı mıyım ?
echo $(stuff)Ne yaptığınızı biliyorsanız , kullanmak isteyebileceğiniz bir neden var . Aynı nedenle, echo $(stuff)ne yaptığınızı gerçekten bilmiyorsanız kaçınmalısınız .
Mesele tam olarak eşdeğerdir stuffve echo $(stuff)değildir. Sonuncusu, çıktısında stuffvarsayılan değer olan split + glob operatörünü çağırmaktır $IFS. Komut ikamesini çift tırnak içine almak bunu önler. Komut ikame işleminden tekli alıntı yapmak artık bir komut ikame işlemi olmamasını sağlıyor.
Bölünme söz konusu olduğunda bunu gözlemlemek için şu komutları çalıştırın:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
Ve globbing için:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Gördüğünüz gibi echo "$(stuff)"eşdeğer (-ish *) ila stuff. Kullanabilirsin ama işleri bu şekilde karmaşıklaştırmanın amacı ne?
Öte yandan eğer istediğiniz çıkışı stuffo zaman globbing bölme + geçmesi olabilir bulmak echo $(stuff)yararlıdır. Yine de bilinçli kararın olmalı.
Değerlendirilmesi gereken (bölücü, globbing ve daha fazlasını içeren) ve kabuk tarafından çalıştırılan çıktı üreten komutlar vardır, bu eval "$(stuff)"da bir olasılıktır ( bu cevaba bakınız ). Ben önce ek bölme + globbing geçmesi çıkışını gereken bir komut görmemiştim baskılı . Kasten kullanmak echo $(stuff)çok nadir görünüyor.
Ne hakkında var=$(stuff); echo "$var"?
İyi bir nokta. Bu pasajı:
var=$(stuff)
echo "$var"
echo "$(stuff)"eşdeğerde (-ish *) ile eşdeğer olmalıdır stuff. Kodun tamamıysa, stuffbunun yerine çalıştırın .
Ancak, stuffbu yaklaşımı bir kereden fazla çıktı kullanmanız gerekiyorsa,
var=$(stuff)
foo "$var"
bar "$var"
genellikle daha iyidir
foo "$(stuff)"
bar "$(stuff)"
Kodunuzda olsa ve kodunuzu girseniz bile foo, bu şekilde tutmak daha iyi olabilir. Düşünülmesi gereken şeyler:echoecho "$var"
- Bir
var=$(stuff) stuffkez çalışır; komut hızlı olsa bile, aynı çıktının iki kez hesaplanmasından kaçınmak doğru şeydir. Belki de stuffstdout'a yazmaktan başka efektler olabilir (örneğin, geçici bir dosya oluşturmak, bir servisi başlatmak, sanal bir makineyi başlatmak, uzak bir sunucuyu bildirmek), bu yüzden birden fazla kez çalıştırmak istemezsiniz.
- Eğer
stuffzaman bağlı veya biraz rasgele çıktı üretir, aralarından tutarsız sonuçlar alabilirsiniz foo "$(stuff)"ve bar "$(stuff)". Sonra var=$(stuff)değeri $varve sabittir emin olabilirsiniz foo "$var"ve bar "$var"aynı komut satırı argümanı olsun.
Bazı durumlarda yerine foo "$var"kullanmak (gereğini) isteyebilirsiniz foo $var, özellikle stuffüretir birden argümanlarını foo(Kabuk desteklediği bunu eğer bir dizi değişkeni daha iyi olabilir). Yine, ne yaptığını biliyorsun. O gelince echoarasındaki fark echo $varve echo "$var"aralarında aynıdır echo $(stuff)ve echo "$(stuff)".
* Eşdeğer ( -ish )?
echo "$(stuff)"Eşittir dedim (-ish) stuff. Tam olarak eşdeğer olmayan en az iki sorun var:
$(stuff)stuffBir alt kabukta çalışır , bu yüzden echo "$(stuff)"eşdeğer (-ish) demek daha iyidir (stuff). Alt kabuklarında çalıştırdıkları kabuğu etkileyen komutlar, ana kabuğu etkilemez.
Bu örnekte stuffolduğu a=1; echo "$a":
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Şununla karşılaştır
a=0
a=1; echo "$a" # stuff
echo "$a"
Ve birlikte
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Başka bir örnek, stuffolmakla başlayın cd /; pwd:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
ve test stuffve (stuff)sürümleri.
echokontrolsüz verileri görüntülemek için iyi bir araç değildir . Bu echo "$var"konuştuğumuz şey olmalıydı printf '%s\n' "$var". Ancak sorudan bahsettiği echove en olası çözüm echoilk etapta kullanmak olmadığı için, printfşimdiye kadar anlatmamaya karar verdim .
stuffveya (stuff)stdout ve stderr çıkışını serpiştirecek, echo $(stuff)tüm (stderr çıktısı olan) stderr çıktısını stuffve yalnızca sonra echo(son çalıştırılan) sindirilen stdout çıktısını yazdıracaktır .
$(…)izleyen her yeni satırdan sıyrılır ve sonra echotekrar eklenir. Bu yüzden echo "$(printf %s 'a')" | xxdfarklı çıktı verir printf %s 'a' | xxd.
Bazı komutlar ( lsörneğin) standart çıktının konsol olup olmamasına bağlı olarak farklılık gösterir; bu yüzden ls | cataynı değil ls. Benzer şekilde echo $(ls)farklı çalışacaktır ls.
lsGenel bir durumda , bu diğer davranışı zorlamanız gerekiyorsa , bir kenara koymak , o stuff | catzaman daha iyidir echo $(ls)veya echo "$(ls)"burada belirtilen diğer tüm sorunları tetiklememektedir.
Muhtemelen farklı çıkış statüsü (bu wiki cevabının eksiksizliği için bahsedilmiştir; ayrıntılar için krediyi hak eden başka bir cevaba bakınız ).