'Ls' ve 'echo $ (ls)' arasındaki fark


27

İki kabuk örneğini göz önünde bulundurun

$ ls
myDoc.html
SomeDirectory
someDoc.txt

ve

$ echo $(ls)
myDoc.html SomeDirectory someDoc.txt

Bunlardan ilki ls, anladığım kadarıyla mevcut çalışma dizininin içeriğini ekleyenleri çalıştırır .stdout terminalin gösterdiği şey) dosyaya . Bu doğru mu?

İkincisi, lskomutun değerini alır (bu, geçerli çalışma dizininin içeriğidir) ve stdoutdosyayı yazdırır . Bu doğru mu?

İki komut neden farklı çıktılar veriyor?


1
çünkü yankı yapıyorsun. Ecs komutuna giriş olarak ls çıktısı.
ankidaemon

Bu, birisinin kısaca açıklayacağı "beklenen" davranış. Ancak, lskendi başına size satır başına birden fazla öğe vermediğinden emin misiniz?
roaima

@roaima kolonize ls, bir bsd "özelliğinin" bir kalıntısıdır. unix sürümleri her satıra bir giriş yazdırır
Steve Cox

@ SteveCox SVR4'ün başından beri düzgün UNIX kullanmadım, bu yüzden hafızam biraz bulanık. Hatırlatma için teşekkürler.
roaima

Neden olmasın echo *?
jdh8

Yanıtlar:


70

Bu komutu çalıştırdığınızda:

ls

terminal, çıktısını görüntüler ls.

Bu komutu çalıştırdığınızda:

echo $(ls)

kabuk, çıktısını yakalar ve üzerinde sözcük ayırma$(ls) işlemini gerçekleştirir . Varsayılan olarak , bu, yeni satır karakterleri dahil tüm beyaz boşluk dizilerinin tek bir boşlukla değiştirildiği anlamına gelir . Bu nedenle çıktısı bir satırda gözüküyor.IFSecho $(ls)

Kelime bölme konusunda ileri düzeyde tartışma için, Greg'in SSS bölümüne bakın .

Kelimenin bölünmesini engelleme

Kabuk, tırnaklarda tırnak içinde sözcük bölme işlemi gerçekleştirmez. Böylece, kelime bölmeyi gizleyebilir ve çok satırlı çıktıyı aşağıdaki şekilde saklayabilirsiniz:

echo "$(ls)"

ls ve çok satırlı çıktı

lsSatır başına bazen birden fazla dosya yazdırdığını fark etmiş olabilirsiniz :

$ ls
file1  file2  file3  file4  file5  file6

Çıkışı lsbir terminale gittiğinde bu varsayılandır . Çıktı doğrudan bir terminale gitmiyorsa ls, varsayılan değerini her satırda bir dosya olarak değiştirir:

$ echo "$(ls)"
file1
file2
file3
file4
file5
file6

Bu davranış belgelenmiştir man ls .

Başka bir incelik: komut değiştirme ve izleyen yeni satırlar

$(...)bir komut ikamesi ve çıkışından satır karakterlerini arka kabuk kaldırır komut ikamesi . Bu normalde farkedilmez, çünkü varsayılan echoolarak çıktısının sonuna bir yeni satır ekler. Eğer sonundan itibaren bir yeni satır kaybedersem Yani, $(...)ve aralarından biri kazanmak echo, herhangi bir değişiklik yoktur. Bununla birlikte, komutunuzun çıktısı yalnızca bir tane eklerken 2 veya daha fazla yeni satır karakteriyle bitiyorsa echo, çıktınızda bir veya daha fazla yeni satır eksik olacaktır. Örnek olarak, printftakip eden yeni satır karakterleri oluşturmak için kullanabiliriz . Aşağıdaki komutların her ikisinin de, farklı sayıda yeni satıra rağmen, bir satırın aynı çıktısını ürettiğini unutmayın:

$ echo "$(printf "\n")"

$ echo "$(printf "\n\n\n\n\n")"

$ 

Bu davranış belgelenmiştirman bash .

Başka bir sürpriz: yol adı genişlemesi, iki kez

Üç dosya oluşturalım:

$ touch 'file?' file1 file2

Arasındaki farkı dikkate ls file?ve echo $(ls file?):

$ ls file?
file?  file1  file2
$ echo $(ls file?)
file? file1 file2 file1 file2

Bu durumda echo $(ls file?), dosya glob'u iki kezfile? genişletilir ve bu da dosya adlarının ve çıktıda iki kez görünmesine neden olur . Bunun nedeni, Jeffiekins'in işaret ettiği gibi, yol adı genişletme işlemi önce kabuk tarafından çalıştırılmadan önce ve sonra tekrar çalıştırılmadan gerçekleştirilir.file1file2lsecho

İkili tırnak işaretleri kullanılırsa, ikinci yol adı genişlemesi engellenebilir:

$ echo "$(ls file?)"
file?
file1
file2

4
ayrıca, isattystdout'un bir tty olup olmadığını kontrol edebilirsiniz; ls, renkleri kullanıp kullanmamayı belirlemek için bunu kullanır.
Janus Troelsen

1
Son kod parçasında alıntılar eşleşmiyor mu? Yoksa $( )aslında bir sözdizimi engeli sağlıyor mu yani enterpolasyon yapmanıza gerek yok mu?
kedi

6
@ cat $(), bir sözdizimi engeli sağlar.
Random832

2
Bir başka önemli fark: Herhangi bir dosya adı bir joker karakter içeriyorsa, echokomut joker karakterini genişletir . Örneğin, eğer dosyayıls döndürürse ? dosya1 dosya2 , sonra dosyaecho $(ls) dönecek ? dosya1 dosya2 dosya1 dosya2 .
Jeffiekins

1
@Jeffiekins echojoker karakterleri genişletmez; Kabuk, ortaya çıkan genişlemeyi argüman olarak iletmeden önce yapar echo.
chepner

0

ls bir terminale çıkış gönderip göndermediğinin farkındadır.

lsBir komut isteminde çalıştırmak yalancı tty'nize yazacaktır. Çıkışını yeniden yönlendirme lsirade genellikle olmayan bir sözde tty olacak olması ve lsfarklı çıkış biçimlendirir.

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.