Kabuk Komutanlığı Yerine Değiştirme, neden yeni bir satır dolgusu yaratır?


25

Aşağıdaki örneğe göre ve son soruma göre , bash'te, takip eden newline char nereye gitti? , "Neden" olduğunu bilmek istiyorum

  x="$(echo -ne "a\nb\n")" ; echo -n "$x" | xxd -p 
# Output is: 610a62 
# The trailing newline from the 'echo' command
#   has been "deleted" by Command Substitution

Orada bazı olmalı varsayalım çok aslında ikame edilir komut çıkışından bazı verileri silmek için, bir kabuk eylem, yani Komuta Değişiklik için önemli sebebi ...
ama görünüyor gibi ben bu bir kafamı alamayan Yapması gereken şeyin antitezi .. yani. Bir komutun çıktısını senaryo işlemine geri döndürmek ... Bir karakteri geri tutmak bana çok garip geliyor ama sanırım bunun mantıklı bir nedeni var ... Bu nedenin ne olduğunu öğrenmeye istekliyim .. .


Yanıtlar:


22

Çünkü kabuk başlangıçta tam bir programlama dili olarak tasarlanmamıştı.

\nBazı komut çıktılarından izi kaldırmak oldukça zor . Bununla birlikte, görüntüleme amacıyla, neredeyse tüm komutlar çıktılarını sonlandırır \n, bu yüzden… başka bir komutta kullanmak istediğinizde onu kaldırmanın basit bir yolu olmalıdır. $()Seçilen çözüm inşaat ile otomatik kaldırma yapıldı.

Belki de bu soruyu cevap olarak kabul edersiniz:

\nAşağıdaki komutta otomatik olarak yapılmazsa, izlemeyi kaldırmanın basit bir yolunu bulabilir misiniz ?

> echo The current date is "$(date)", have a good day!

Biçimlendirilmiş tarihlerde görünebilecek çift boşlukların parçalanmasını önlemek için alıntı yapılması gerektiğini unutmayın.


1
Söylediklerin doğruysa, o zaman kesinlikle şaşırırdım. Bir varsa shoptsizin tarif varsayılan davranışını değiştirmek için, sonra yine mutlu olurdum ... Ben zor Bash / Linux / Unix sırf "stdout'u yakalayan" gibi kritik bir işlevi kirletmez olacağını düşünmek bulmak datezorunda değildir '/ n' seçeneği olan / olmayan ... Açık düzeltme, bash (veya başka bir kabuğun) bunun shoptiçin bir olacağıdır ... Herhangi bir şey biliyor musunuz? .. ve bu ihsanın nedenini ve nerede olduğunu söyleyen herhangi bir referans bağlantınız var mı? ... ve neden datebir \ n seçeneği yok .. Olmalı!
Peter.O

2
Komut ikameleri Bourne kabuğunun ilk versiyonunda 1979'da Unix'in "7. baskısında" ortaya çıktı. Zaten büyük bir devrimdi ve sanırım kimsenin '\ n' izini sürüp sürdürmemeyi umursamadığı (doğmadım). Evet, man sayfasını 10 dakikadan daha az bir sürede okuyabilirsiniz ve komut değiştirme konusunda o zamana kadar hiçbir şey değişmemiş gibi görünüyor. Tercih edilen $()alternatif sözdizimi hariç .
Stéphane Gimenez

Teşekkürler .. Bunun eski bir sorun olabileceğini düşündüm ve kesinlikle Komuta Değişikliklerimi daha dikkatli izlemeye başladığım gerçeğini şekillendiriyor. Bugüne kadar bir kanatta hayatta kalmak zorunda kaldım ve dua ettim .. Karşılaştığım bu "gizemli olayların" bazıları şimdi anlam kazanmaya başlıyor :) ... Yani "randevu" sıranızın tam tersi durumda { echo -n "The current date is "; var="$(date; echo -e x)"; var="${var%x}"; echo -n "$var"; echo ", have a good day!"; }
İzlerime

Not: Benim yukarıdaki yorumum: Tabii ki, sadece dateişe date
yarardı

Hakkında 'sorusu' tarih anlayışıma doğru güçlü promt oldu Komuta Substution bu soruma 'en iyi' cevabı olmuştur bu yüzden, does ... ve kesinlikle de diğer iyi cevaplar gerektiği gibi iyi yapar 'niçin' ..
Peter.O

19

Standardın bir parçası :

Kabuk, bir alt kabuk ortamında (bkz. Shell Yürütme Ortamı ) komutu yürüterek ve komut değiştirmeyi ( komut metni artı "$ ()" ekini ya da geri tırnakları) komutun standart çıktısıyla değiştirerek komut değiştirmeyi genişletecektir. ikame sonunda bir veya daha fazla <yeni hat> sekansları.

Elbette, standart muhtemelen bu şekilde yazılmıştır, çünkü kshböyle veya böyle bir şey yaptı, ancak standart ve belgelendirilmiş davranış. Eğer beğenmediysen, Perl ya da takip eden yeni hatları korumanıza izin verecek başka bir şey kullanın.


Güzel bir özeti .. Teşekkürler .. ve bağlantılar kesinlikle yardımcı oldu
Peter.O 31:11

4
Standart böyledir, çünkü Bourne kabuğunun böyle yaptığı ve o zamandan beri diğer tüm kabukları yaptığı gibi.
Gilles 'SO- kötü olmayı durdur' 21

6

Bana mantıklı geliyor. Newline, yalnızca ilk sırada, normal komut çıktısında bulunur, böylece komut yeni bir satırda tamamlandıktan sonra bilgi istemi görünür. Newline çoğu durumda orijinal çıktının bir parçası değildir, ekranı düzeltmek için oradadır. Bir komutun çıktısını ayrıştırırken en sondaki yeni satır genellikle zahmetlidir. wcKomut neden 2 satır metin veriyor? Oh, öyle değil, birini yeni bir satır takip eder. Ayrıştırdığınızda wc, 2 satırlık çıktı olduğu için endişelenmek istemezsiniz - gerçekten yok, sadece bir tane var.


@EightBitTony: Sorum terminalde bir şey göstermeyle ilgili hiçbir şekilde değildir. Bu oldukça yalındır. Görüntülenecek yeni bir satır varsa, o zaman yeni satır görüntülenecektir. Burada söz konusu \nolan, orjinal stdoutakıştaki a'nın Komut Değiştirme tarafından kaldırılmasıdır. yani. orijinal verilerimde (çok önemli veriler) veriler "tırnak işaretleri" içinde olsa bile, izleyen satır sonları kaldırıldı. Word Splitting'in nasıl ve neden işe yaradığını makul bir şekilde anlıyorum, ancak Komut Değiştirme'nin neden sadece yeni satırları ve sadece son satırları çıkardığını kesinlikle bilmiyorum .
Peter.O

1
Söylediğiniz hiçbir şey görüşümü değiştirmiyor. Çoğu zaman, herhangi bir çıktıdaki son yeni satır, verilerin bir parçası olarak değil, yalnızca görüntüleme amaçlıdır.
EightBitTony

Ben senin görüşüne katılıyorum ve sonunda çıktı newline Evet ... Baştan sahip olduğu kolaylık ... ama sorunum ... Soruyorum bununla ilgisi yok: Neden Komut değişikliği zorla çıkarmak yok ? ... Bunlar iki farklı meseledir. Belki de sorum şu olmalı: Yerleşik bir geçici çözüm var mı? . çünkü son bir kukla karakter ekleyerek bu sorunu kodlamak zorunda kalıyor, berbat! ... mecbur kalırsam yapacağım, ama ilk defa bash tarafından engellendiğim (ve şok durumdayım :) .. Çok iyi gidiyor ...
Peter.O

Başka bir cevapta belirtildiği gibi, standardın bir parçasıdır. Benim için, bu şekilde olduğunu düşünüyorum çünkü verileri işlemden geçirdiğinizde uygun veri hattını değil sadece verileri görmek istiyorsunuz. Bunun nedeni, kabuğun bir borudaki verileri işlemenizi beklediği ve yeni satırın veri olmadığıdır. Daha fazla ve bunu bir tartışmaya götürmemiz gerekiyor.
EightBitTony

Teşekkürler .. Şimdi fikrimi çok iyi anladım .. Komuta Yerine Geçme örneği basitçe izlemekten ziyade takip eden yeni hatları bırakmaya yöneliyor gibi görünüyor. Onları korumaktan hoşlanmam. "ama, dosya adlarındaki bütün büyük harflerin ezici popüler kullanımının biraz garip / gereksiz olduğunu düşünürdüm, ama geçen gün aslında oldukça rahat bir sistem olduğunu düşünüyordum. Muhtemelen bakın (daha derinden) Komuta Yerine
Takma

1

Aynı sorunla karşı karşıyaydım ve aşağıda da örnek bulundu. Alıntı yapmak bu duruma yardımcı oldu gibi görünüyor, en azından benim için yaptı:

http://tldp.org/LDP/abs/html/commandsub.html .

dir_listing=`ls -l`
echo $dir_listing     # unquoted

# Expecting a nicely ordered directory listing.

# However, what you get is:
# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh

# The newlines disappeared.


echo "$dir_listing"   # quoted
# -rw-rw-r--    1 bozo       30 May 13 17:15 1.txt
# -rw-rw-r--    1 bozo       51 May 15 20:57 t2.sh
# -rwxr-xr-x    1 bozo      217 Mar  5 21:13 wi.sh

2
İşte burada neler oluyor. $strDize içeren bir değişkeniniz olduğunu varsayalım "a b c". Eğer geçerseniz $striçin echotırnak (olmadan echo $str), echoalacak a, bve cüç ayrı bağımsız değişkenleri. Kabuğunuz argümanlar arasındaki boşlukla ilgilenmiyor. echosonra argümanları birbirinden ayıran boşluklarla yazdıracaksınız "a b c". Değişkeni, echoetrafında tırnaklarla ( echo "$str") geçirirseniz, kabuk, onu bir argüman olarak görür ve echoböyle alır, bu nedenle boşluklar daraltılmaz. Aynısı yeni hatlar için de geçerlidir.

1
Orijinal posterin sahip olduğu sorun, emirlerinin yeni takip eden satırlarının (sadece sonuncusu) kaybolmasıdır. -nBayrağı geçmediği sürece echo, çıkışına izleyen bir yeni satır ekler, bu nedenle örneğinizdeki her iki ekosun izleyen yeni satırları vardır. Ancak, denerseniz echo -n $dir_listingveya denerseniz echo -n "$dir_listing", hiçbir sondaki yeni satırın tırnak işaretleri ile veya tırnaklar olmadan yazdırılmadığını göreceksiniz; $dir_listingbu, sorunun komutun yerine koyulmasıyla ilgili olduğunu gösterir.

2
Tldp kabuk komut dosyası hakkında bilgi edinmek için çok eski bir yer. Bunun yerine Wooledge Bash Wiki'yi deneyin. mywiki.wooledge.org/BashGuide
Wildcard

-1

echo "hello "(tırnak işaretleri olmadan) neden boşluğu dolduruyor? IFS karakterlerinin değeri kabuk tarafından sınırlayıcı olarak görülür, bunun için izleyenler (hiçbir şeyi sınırlamayan) kaldırılır. commend ikamesi, sadece bir sub-shell'de övgüler uygulayan düzdür, bu yüzden aynı mantığı izler.


@Philomath: Hem x="hello  "ve x="hello     "kaybedecek tüm aracılığıyla gösteriliyorsa, bunların sonunda boşluk echo $x... Ancak sadece en son Komuta Substituton ait satır kaybolur.
Peter.O

garip, bash'ımda herhangi bir fark görmüyorum (xxd ile doğrulama)
Philomath

Ben sadece bunu kontrol ediyorum ... Tüm takip eden yeni satırları kaldırıyor ... Bu izlenimi elde ettiğimde IFS ile denemeler yapıyordum, öyleyse bunu iptal edelim :) .. ama soru hala devam ediyor ... Bu çok önemli bir bölüm sözcük bölme tek alana birden çok boşluğu yoğunlaşmasına ve tamamen baştaki ve sondaki boşlukları kaldırmak için .. ben yapabilirsiniz anlıyorum ama, Komut Değişiklik ile, bu yüzden kesinlikle anlamıyorum sadece olarak (şeritler \ n ve tüm boşluk kelime bölme ile), ve neden sadece sonun sonu? .. ve hepsinden önemlisi: "Komut Değiştirme" sadece kısmen ikame edilir .. Neden?
Peter.O

4
IFSkomut değiştirmelerin sonunda yeni satırları çıkarmakla bir ilgisi yok.
Gilles 'SO- kötülük yapmayı bırak'
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.