2012-07-05 21 views
63

Thông thường, stdout là bộ đệm dòng. Nói cách khác, miễn là đối số printf của bạn kết thúc bằng một dòng mới, bạn có thể mong đợi dòng được in ngay lập tức. Điều này dường như không giữ khi sử dụng đường ống để chuyển hướng đến tee.Buộc dòng đệm khi xuất xưởng khi đường ống đến tee

Tôi có chương trình C++, a, kết quả đầu ra chuỗi, luôn là \n -terminated, đến stdout.

Khi nó được tự chạy (./a), mọi thứ đều in chính xác và vào đúng thời điểm, như mong đợi. Tuy nhiên, nếu tôi gửi nó đến tee (./a | tee output.txt), nó sẽ không in bất cứ thứ gì cho đến khi thoát, điều này sẽ đánh bại mục đích sử dụng tee.

Tôi biết rằng tôi có thể sửa lỗi bằng cách thêm fflush(stdout) sau mỗi thao tác in trong chương trình C++. Nhưng có cách nào sạch hơn, dễ hơn không? Có một lệnh tôi có thể chạy, ví dụ, mà sẽ buộc stdout để được dòng đệm, ngay cả khi sử dụng một đường ống?

Trả lời

26

Hãy thử unbuffer là một phần của gói expect. Bạn có thể đã có nó trên hệ thống của bạn.

+0

Cảm ơn, điều này đã làm việc, mặc dù tôi đã phải biên dịch ' mong đợi' bản thân mình là 'unbuffer' dường như không được đưa vào mặc định trong OS X. – houbysoft

+0

@houbysoft: Tôi rất vui vì nó đã làm việc cho bạn. 'unbuffer' chỉ là một tập lệnh nhỏ nên bạn không cần phải biên dịch lại toàn bộ gói. –

+0

Vâng, có thể không, nhưng './configure && make' mất khoảng 10 giây và sau đó tôi chỉ chuyển' unbuffer' sang '/ usr/local/bin' :) – houbysoft

81

bạn có thể thử stdbuf

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

(lớn) là một phần của trang người đàn ông:

-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. 

ghi nhớ điều này, mặc dù:

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. 

bạn không chạy stdbuf trên tee, bạn đang chạy nó trên a, vì vậy điều này không ảnh hưởng đến bạn, trừ khi bạn đặt bộ đệm của các luồng của a trong nguồn của a.

Ngoài ra, stdbufkhông POSIX, nhưng là một phần của GNU-coreutils.

+2

Cảm ơn, nhưng điều này dường như không có sẵn trên OS X (câu hỏi được gắn thẻ là osx-lion). – houbysoft

+1

@houbysoft - Tôi khá chắc chắn các công cụ GNU có thể được cài đặt trên OS X – jordanm

+1

@jordanm: có lẽ, nhưng cài đặt toàn bộ các công cụ GNU loại có vẻ như quá mức cần thiết cho việc này ... – houbysoft

1

Nếu bạn sử dụng các lớp luồng C++ thay thế, mỗi std::endl một lần xả ngầm ẩn. Sử dụng in theo phong cách C, tôi nghĩ phương pháp bạn đề xuất (fflush()) là cách duy nhất.

+2

Thật không may, điều này không đúng. Bạn có thể quan sát cùng một hành vi với C++ std :: cout ngay cả khi sử dụng std :: endl hoặc std :: flush. Việc đệm xảy ra trên đầu và giải pháp đơn giản nhất trong Linux có vẻ là setlinebuf (stdout); là dòng đầu tiên trong main() khi bạn là tác giả của chương trình và sử dụng các giải pháp khác ở trên khi không thể thay đổi mã nguồn. – oxygene

+0

@oxygene Điều này không đúng. Tôi đã thử nó và endl không tuôn ra bộ đệm khi đường ống để tee (không giống như với printf). Mã: '#include #include int main (void) {std :: cout <<" 1 "<< std :: endl; ngủ (1); std :: cout << "2" << std :: endl; } '. endl luôn luôn xóa bộ đệm như được định nghĩa ở đây: http://en.cppreference.com/w/cpp/io/manip/endl –

23

Bạn cũng có thể thử thực hiện lệnh của mình trong một thiết bị đầu cuối giả sử dụng lệnh script (điều này sẽ buộc thực thi đầu ra đệm vào đường ống)!

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

Lưu ý lệnh script không truyền lại trạng thái thoát của lệnh được bao bọc.

+2

'script -t 1 /path/to/outputfile.txt./a' làm việc tuyệt vời cho tôi trường hợp sử dụng. Nó phát trực tiếp tất cả các đầu ra đến 'outputfile.txt' trong khi cũng in nó vào trình bao của bạn. Không cần phải sử dụng 'tee' –

12

Bạn có thể sử dụng setlinebuf từ stdio.h.

setlinebuf(stdout); 

Điều này sẽ thay đổi bộ đệm thành "dòng đệm".

Nếu bạn cần linh hoạt hơn, bạn có thể sử dụng setvbuf.

+2

Tôi tự hỏi tại sao giải pháp này có quá ít upvotes. Đây là giải pháp duy nhất không áp đặt gánh nặng cho người gọi. – oxygene

Các vấn đề liên quan