T'ye boru döşenirken standart çıkışın hat tamponlamasını zorla


118

Genellikle stdoutsatır ara belleğe alınır. Başka bir deyişle, printfargümanınız bir satırsonu ile bittiği sürece , satırın anında basılmasını bekleyebilirsiniz. Yönlendirme için bir boru kullanırken bu geçerli görünmüyor tee.

C ++ programım var, adizeleri her zaman \n-sonlandırılmış stdout.

Kendi başına çalıştırıldığında ( ./a), her şey beklendiği gibi doğru ve doğru zamanda yazdırılır. Ancak, tee( ./a | tee output.txt) 'ye yönlendirirsem, çıkana kadar hiçbir şey yazdırmaz, bu da kullanım amacını bozar tee.

fflush(stdout)C ++ programında her yazdırma işleminden sonra bir ekleyerek düzeltebileceğimi biliyorum . Ama daha temiz ve daha kolay bir yol var mı? Örneğin, stdoutbir boru kullanırken bile satır tamponlamaya zorlayacak çalıştırabileceğim bir komut var mı ?

Yanıtlar:


67

unbufferHangisinin expectpaketin parçası olduğunu deneyin . Zaten sisteminizde olabilir.

Sizin durumunuzda bunu şu şekilde kullanırsınız:

./a | unbuffer -p tee output.txt

( -punbuffer'ın stdin'den okuduğu ve argümanların geri kalanında komuta ilettiği boru hattı modu içindir)


Teşekkürler, bu işe yaradı, ancak expectkendimi unbufferOS X'e varsayılan olarak dahil edilmemiş gibi derlemek zorunda kaldım .
houbysoft

@houbysoft: Senin için çalıştığına sevindim. unbuffersadece küçük bir betik olduğundan, tüm paketi yeniden derlemenize gerek kalmamalıydı.
sonraki duyuruya kadar duraklatıldı.

Evet, muhtemelen değil, ama ./configure && make10 saniye sürdüğü ve sonra sadece taşındı unbufferiçin /usr/local/bin:)
houbysoft

3
Mac'ime (10.8.5) brew aracılığıyla yükledim: brew install wait --with-brewed-tk
Nils

2
FWIW, unbuffer biraz kafa karıştırıcı olduğu için, ilgili yapı unbuffer {commands with pipes/tee}.
Sahte İsim

128

deneyebilirsin stdbuf

$ stdbuf -o 0 ./a | tee output.txt

man sayfasının (büyük) bölümü:

  -i, --input=MODE   adjust standard input stream buffering
  -o, --output=MODE  adjust standard output stream buffering
  -e, --error=MODE   adjust standard error stream buffering

If MODE is 'L' the corresponding stream will be line buffered.
This option is invalid with standard input.

If MODE is '0' the corresponding stream will be unbuffered.

Otherwise MODE is a number which may be followed by one of the following:
KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.
In this case the corresponding stream will be fully buffered with the buffer
size set to MODE bytes.

yine de şunu aklınızda bulundurun:

NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does
for e.g.) then that will override corresponding settings changed by 'stdbuf'.
Also some filters (like 'dd' and 'cat' etc.) dont use streams for I/O,
and are thus unaffected by 'stdbuf' settings.

Eğer yayınlanmıyor stdbufüzerinde teebunu üzerinde yayınlıyorsunuz, abu sizi etkilememelidir böylece yüzeyine tampon set sürece, a's akışları as kaynak'.

Ayrıca, stdbufbir değil POSIX ama GNU-coreutils parçası.


3
Teşekkürler, ancak bu OS X'de mevcut görünmüyor (soru osx-lion olarak etiketlenmiştir).
houbysoft

2
@houbysoft - GNU araçlarının OS X'e yüklenebileceğinden oldukça eminim
jordanm

1
@jordanm: belki, ama tüm GNU araçlarını kurmak bunun için biraz fazla gözüküyor ...
houbysoft

1
Bu yanıta olumlu oy verildi çünkü stdbufkullandığımız Centos Linux dağıtımlarında zaten mevcut ve unbufferdeğil. Teşekkürler!
Huw Walters

6
Python betiği için stdbuf çalışmaz, ancak -upython tarafında arabelleğe almayı devre dışı bırakmak için kullanabilirsiniz :python3 -u a.py | tee output.txt
Honza

27

Ayrıca komutu kullanarak bir sözde terminalde komutunuzu çalıştırmayı deneyebilirsiniz script(bu, boruya satır tamponlu çıktıyı zorunlu kılar)!

script -q /dev/null ./a | tee output.txt     # Mac OS X, FreeBSD
script -c "./a" /dev/null | tee output.txt   # Linux

Unutmayın scriptkomut sarılmış komutun çıkış durumu geri yaymak değil.


3
script -t 1 /path/to/outputfile.txt ./akullanım durumum için harika çalıştı. Tüm çıktıları canlı olarak yayınlarken outputfile.txtaynı zamanda kabuğunuzun standart çıkışına yazdırır. Kullanmaya gerek yoktutee
Peter Berg

26

Stdio.h adresinden setlinebuf'u kullanabilirsiniz.

setlinebuf(stdout);

Bu, tamponlamayı "satır tamponlu" olarak değiştirmelidir.

Daha fazla esnekliğe ihtiyacınız varsa setvbuf'u kullanabilirsiniz.


8
Bu çözümün neden bu kadar az olumlu oyu olduğunu merak ediyorum. Arayan kişiye yük getirmeyen tek çözüm budur.
oxygene

1
Bunun standart C (hatta POSIX) olmadığını unutmayın. Muhtemelen kullanmak daha iyidir setvbuf(stdout, NULL, _IOLBF, 0), ki bu tam olarak eşdeğerdir.
rvighne

Bu, OS X Catalina'daki sorunumu printf () ing olan bir C ++ programıyla düzeltti ve ben tişörte boruluyordum, ancak çıktıyı yalnızca program bittiğinde görüyordu.
jbaxter

2

Bunun yerine C ++ akış sınıflarını kullanırsanız, her std::endl biri örtük bir yıkamadır. C tarzı yazdırmayı kullanarak, önerdiğiniz yöntemin ( fflush()) tek yol olduğunu düşünüyorum .


4
Ne yazık ki bu doğru değil. Std :: endl veya std :: flush kullanırken bile c ++ std :: cout ile aynı davranışı gözlemleyebilirsiniz. Arabelleğe alma üstte gerçekleşir ve Linux'taki en kolay çözüm setlinebuf (stdout) gibi görünür; programın yazarı olduğunuzda main () 'in ilk satırı ve kaynak kodunu değiştiremediğinizde yukarıdaki diğer çözümleri kullanın.
oxygene

1
@oxygene Bu doğru değil. Denedim ve endl, tampona boru döşerken tamponu temizliyor (printf'den farklı olarak). Kod: #include <iostream> #include <unistd.h> int main(void) { std::cout << "1" << std::endl; sleep(1); std::cout << "2" << std::endl; }. endl her zaman burada tanımlandığı gibi tamponu temizler: en.cppreference.com/w/cpp/io/manip/endl
Curtis Yallop

0

Bir sonraki duyuruya kadar @Paused adresindeki paketin unbufferkomutuexpect yanıtı, sunulduğu şekilde benim için işe yaramadı.

Kullanmak yerine:

./a | unbuffer -p tee output.txt

Kullanmalıydım:

unbuffer -p ./a | tee output.txt

(-punbuffer'ın stdin'den okuduğu ve argümanların geri kalanında komuta ilettiği boru hattı modu içindir)

expectPaket yüklenebilir:

  1. MSYS2 ile pacman -S expected
  2. Mac OS brew install expected
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.