Borular, bir boru hattında veri akışı nasıl?


22

Verilerin boru hattında nasıl aktığını anlamıyorum ve birinin orada neler olduğunu açıklığa kavuşturmasını umuyorum.

Komutlar dizisi dosyaları (metin, dizeler dizileri) satır sıraya göre işler. (Her komutun kendisi satır satır çalışır.) Her metin satırı boru hattından geçer, komutlar bir önceki öğenin tüm girişi işlemeyi bitirmesini beklemez.

Ama öyle görünmüyor.

İşte bir test örneği. Bazı metin satırları var. Onları büyük harcar ve her satırı iki kez tekrarlarım. Ben de yapıyorum cat text | tr '[:lower:]' '[:upper:]' | sed 'p'.

Süreci takip etmek için "etkileşimli olarak" çalıştırabiliriz - giriş dosya adını atlayın cat. Boru hattının her bölümü satır satır çalışıyor:

$ cat | tr '[:lower:]' '[:upper:]'
alkjsd
ALKJSD
sdkj
SDKJ
$ cat | sed 'p'
line1
line1
line1
line 2
line 2
line 2

Ancak boru hattının tamamı girişi bitirmemi bekler EOFve sonucu ancak yazdırır:

$ cat | tr '[:lower:]' '[:upper:]' | sed 'p'
I am writing...
keep writing...
now ctrl-D
I AM WRITING...
I AM WRITING...
KEEP WRITING...
KEEP WRITING...
NOW CTRL-D
NOW CTRL-D

Öyle olması mı gerekiyor? Neden satır satır değil?


Boru değil, catstdin kapanana kadar tamponlama yapıyor.
goldilocks

ama trve stdin kapanmadan önceki sedsüreç çizgileri yapmakcat
xealits 21

Stdio tarafından kullanılan varsayılanlar (belirtilen programların hepsinin kullandığına inanıyorum), stderr'in arabelleğe alınmamış olduğu ve stdout'un bir terminale yazarken satır arabelleğe alındığı ve aksi takdirde tam olarak arabelleğe alındığı (örneğin bir dosyaya veya bir boruya yazıyorsa) . Komutların bazılarında stdout arabelleğini değiştirebilecek bayraklar var, ancak tr gibi görünmüyor.
kasperd

Yanıtlar:


36

stdioÇoğu unix programının kullandığı C standart G / Ç kütüphanesi ( ) tarafından takip edilen genel bir tamponlama kuralı var . Çıkış bir terminale gidiyorsa, her satırın sonunda temizlenir; Aksi halde, yalnızca tampon (Linux / amd64 sistemimde 8K; sizinkinde farklı olabilir) dolu olduğunda temizlenir.

Tüm kamu hizmetleri genel kural şu olsaydı, çıkış senin örneklerin tümünde gecikmiş görecekti ( cat|sed, cat|trve cat|tr|sed). Ancak bir istisna var: GNU cathiçbir zaman çıktısını tamponlamaz. Ya kullanmaz stdioya da varsayılan stdiotamponlama politikasını değiştirir.

GNU’yu kullandığınızdan eminim, catbaşka bir unix catdeğil, diğerleri böyle davranmaz. Geleneksel unix'in tamponlanmamış çıktı talep etme seçeneği catvardır -u. GNU catbu -useçeneği görmezden geliyor çünkü çıktı her zaman arabelleksiz.

Bu yüzden cat, solda bir boruya sahip olduğunuzda , GNU sisteminde, borudan verilerin geçişi gecikmeyecektir. catHatta satır satır gitmiyor - Terminal o yapıyor. Cat için giriş yazarken, terminaliniz "kanonik" moddadır - satır tabanlıdır, backspace ve ctrl-U gibi düzenleme tuşları ile size göndermeden önce yazdığınız satırı düzenleme şansı sunar Enter.

In cat|tr|sedÖrneğin, trhala veri alıyor catolarak basar basmaz Enter, ama trtakip ediyor stdioher satırdan sonra floş değil bu yüzden, onun çıkış bir boruya gidiyor: Varsayılan politika. Tampon dolduğunda veya hangisi önce gelirse, bir EOF alındığında ikinci boruya yazar.

sedaynı zamanda stdiovarsayılan politikayı da takip ediyor , ancak çıktısı bir terminale gidiyor, böylece her satırda bittiği anda yazacak. Bu boru hattının diğer ucundaki kadar bir şey gösterilmeden önce yazmalısınız ne kadar üzerinde bir etkisi vardır - eğer sedoldu blok tamponlama çıktısı, çok (dolgu olarak iki kez yazmak zorunda ediyorum tr'çıktı tamponunun ler ve sed ' ın çıkışını tampon).

GNU seçeneğine sedsahiptir, -ueğer emri tersine çevirirseniz ve kullandıysanız cat|sed -u|tr, çıktının anında tekrar göründüğünü görürsünüz. ( sed -uSeçenek başka bir yerde mevcut olabilir ama bunun gibi eski bir unix geleneği olduğunu sanmıyorum cat -u) Söyleyebileceğim kadarıyla eşdeğer bir seçenek yok tr.

Varsayılanları stdbufkullanan herhangi bir komutun tamponlama modunu değiştirmenize izin veren bir yardımcı program vardır stdio. LD_PRELOADC kütüphanesinin desteklemesi için tasarlanmadığı bir şeyi başarmak için kullandığı için biraz kırılgandı , ancak bu durumda işe yarıyor gibi görünüyor:

cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'

1
Teşekkürler! Müthiş cevap. Muhtemelen sorudaki tamponlamadan bir şekilde bahsetmeliyim ki onu bulabilirim.
xealits,

teeve ddayrıca genellikle kendi kurallarına göre oynarlar. Yaratıcı olarak birleştirildiğinde, üç araç stdbufarka planlı boru hatlarına olan herhangi bir ihtiyacı oldukça taşınabilir bir şekilde reddedebilir .
mikeserv

1
Bu, işe yaramaz kedi kullanımını engellemenin sebeplerinden biridir .
Ocaklar

8

Bu aslında bana anlamak için bazı düşünceler aldı ve cevaplamak için daha da fazlasını verdi. Harika bir soru (daha sonra oylayacağım).

tr | sedYukarıdaki hata ayıklama öğelerinizi denemeyi ihmal ettiniz :

>tr '[:lower:]' '[:upper:]' | sed 'p'
i am writing
still writing
now ctrl-d
I AM WRITING
I AM WRITING
STILL WRITING
STILL WRITING
NOW CTRL-D
NOW CTRL-D
>

Bu yüzden açıkça trtamponlar. Her gün yeni bir şeyler öğren!

EDIT :

Bunu düşündüğüm gibi, sebebi izole ettik, ancak bir açıklama yapmadık. Eğer varsa cat | treğer, bu, hemen yazıyor cat | sed, bu hemen yazıyor, ama eğer tr | sed, o bekler için EOF. Cevabın o zaman trya da sedkaynak koduna gömülmüş olabileceğini ve bunun bir sorun olmadığını söyleyebilirim .

EDIT :

Son düzenlemeyi yazarken, Wumpus'un açıklamayı yaptığını görüyorum. Teşekkürler!


1
gerçekten onlar tampon! ve Wumpus'un da belirttiği gibi, kabaca 8 kb çizgileri olan test, tamponun gerçekten 8 KB olduğunu göstermektedir. Etrafında bazı üne sahip olmak için her iki cevabı da kabul etmek isterdim, ancak Wumpus’un daha eksiksiz bir cevap alacağım. Yine de teşekkürler!
xealits,

1
Hiç sorun değil, benimki ampirik cevaptı, onun bilgili oldu.
Poisson Aerohead

Nasıl kullanılacağını gösteren bu soruyu stdbufda faydalı olabilir. unix.stackexchange.com/questions/182537/…
Joe
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.