Line Buffered Cat
No, but GNU grep with --line-buffered
can do this. Just search for something every line has, such as '^'
.
Force line-buffering of stdout in a pipeline
Try unbuffer
(man
page) which is part of the expect
package. You may already have it on your system.
In your case you would use it like this:
unbuffer ./a | tee output.txt
The -p
option is for pipeline mode where unbuffer reads from stdin and passes it to the command in the rest of the arguments.
What do fully buffered, line buffered and unbuffered mean in C?
Online C11 standard, 7.21.3/3:
When a stream is unbuffered, characters are intended to appear from the source or at the destination as soon as possible. Otherwise characters may be accumulated and transmitted to or from the host environment as a block. When a stream is fully buffered, characters are intended to be transmitted to or from the host environment as a block when a buffer is filled. When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment. Support for these characteristics is implementation-defined, and may be affected via the
setbuf
andsetvbuf
functions.
7.21.3/7:
At program startup, three text streams are predefined and need not be opened explicitly — standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
Piping the output to cat
That's because printf
's output will get buffered by the libc
, write
's output will not get buffered. It's a direct, unbuffered operation on a file (stdout)
Read this:
if stdout is a terminal then buffering is automatically set to line buffered, else it is set to buffered
So, you are actually piping to cat
- that's why buffering is enabled (try without cat
to see)
To turn off the buffering issue the stdbuf
command:
stdbuf -o0 ./a.out | cat
By the way, that's a really good question to ask for someone who isn't an every day C hacker! Simple and descriptive!
Turn off buffering in pipe
You can use the unbuffer
command (which comes as part of the expect
package), e.g.
unbuffer long_running_command | print_progress
unbuffer
connects to long_running_command
via a pseudoterminal (pty), which makes the system treat it as an interactive process, therefore not using the 4-kiB buffering in the pipeline that is the likely cause of the delay.
For longer pipelines, you may have to unbuffer each command (except the final one), e.g.
unbuffer x | unbuffer -p y | z
pipeline command ./a.out | cat, printf(line\n) in a.out is not excuted and no output
An output stream can be in one of three different modes, unbuffered, line buffered, or fully buffered. In unbuffered mode, output is written immediately. In line buffered mode, output is written first to an internal stream buffer until the buffer is full or a newline is written, and then the buffer is flushed to the output. In fully buffered mode, the output is written first to an internal stream buffer until the buffer is full, and then the buffer is flushed to the output. (Some implementations may also flush the output at other times, such as when reading input from an interactive device.)
Input streams can also be in the same three modes, and this determines when read input is made available to the caller of functions that read streams.
The implementation initializes the mode of the standard input (stdin
), standard output (stdout
), and standard error output (stderr
) streams before the main
function is called (or at least before any access to the streams). Under certain circumstances, the implementation is allowed to initialize the standard input or standard output to fully buffered mode. The standard input and output streams are initialized to fully buffered mode if and only if the implementation can determine that they are not linked to an interactive device (such as a terminal). (The standard error output stream is never initialized to fully buffered mode.)
Typically, the C runtime library of a POSIX system will call isatty
on the underlying file descriptors for the standard input and output streams and set the streams to fully buffered mode if isatty
returns 0. This occurs before the main
function is called.
When you run "./a.out" with output going to the terminal, the C runtime library determines that output is going to an interactive device and does not set stdout
to fully buffered mode. It will be set to one of the other modes, typically line buffered mode. However, when you run "/a.out" with output going to a pipe, the C runtime library determines that output is not going to an interactive device and does set stdout
to fully buffered mode. This is why the output is not written to the pipe immediately.
There are two ways to solve your problem. The first is to change the standard output stream to line buffered mode or unbuffered mode before the first call to printf
:
setvbuf(stdout, NULL, _IOLBF, 0); // set standard output to line buffered mode
setvbuf(stdout, NULL, _IONBF, 0); // set standard output to unbuffered mode
The other way is to to flush the standard output on demand:
fflush(stdout); // write buffered standard output contents
How can I wrap a command with a line-buffered prompt?
First of all, I was wrong about rlwrap, you can use a prompt with it:
rlwrap -S "> " grep hi
And it works pretty well. But it leaves artifacts of the prompt if you have something typed when something is printed by the process.
Then I found socat, and it can do essentially the same thing as the above (among other things), but it doesn't leave those artifacts (by blocking stdout while you type until you press enter and the line is clear again):
socat READLINE,prompt="[IN] " EXEC:"stdbuf -oL grep hi"
[IN] hello
[IN] this is another example
this is another example
[IN] it sure is, i'm glad you know
Then I can just use sed to add a prompt to the output:
socat READLINE,prompt="[IN] " SYSTEM:"stdbuf -oL grep hi | stdbuf -oL sed \'s/^/[OUT] /\'"
[IN] hello
[IN] this is another example
[OUT] this is another example
[IN] it sure is, i'm glad you know
Line buffering in a bash coproc
One way to force line-buffering is to use the stdbuf
coreutils tool, if available:
stdbuf
allows one to modify the buffering operations of the three standard I/O streams associated with a program.
For the coproc
case:
$ coproc stdbuf -oL paste
[3] 42751
$ echo 'Hello world!' >&${COPROC[1]}
$ read -ru ${COPROC[0]} line; echo $line
Hello world!
$ kill $COPROC_PID
[3]+ Terminated coproc COPROC stdbuf -oL paste
$
For the simple pipe of paste
to cat
case:
$ stdbuf -oL paste | cat
Hello World!<RETURN>
Hello World!^D
$
unix command 'tail' lost option '--line-buffered'
As far as can be told by simple googling, tail
doesn't appear to have a --line-buffered
option, grep
does. --line-buffered
is useful to force line buffering even when writing to a non-TTY, a typical idiom being:
tail -f FILE | grep --line-buffered REGEXP > output
Here the point of --line-buffered
is to prevent grep
from buffering output in 8K chunks and forcing the matched lines to immediately appear in the output file.
tail -f
is unbuffered regardless of output type, so it doesn't need a --line-buffered
option equivalent to the one in grep
. This can be verified by running tail -f somefile | cat
and appending a line to the file from another shell. One observes that, despite its standard output being a pipe, tail
immediately flushes the newly arrived line.
Related Topics
Insufficient Permission Pushing to Git Shared Repo Over Smart Http
How to Use/Learn Video4Linux2 (On Screen Display) Output APIs
How Do Parent and Child Share Pages After Fork() with Copy-On-Write in Linux
How Event Packet Header Is Getiing in Hci_Send_Req API Implementation
What Special Meaning Does an Equal-Sign Have in Zsh
Apt-Update in Azure Nvidia Gives Publickey Error
How to Run Sh File from Another Sh File
Need Some Advise to Begin Programming on Arm (With Linux) Platform
How to Compile a Node C++ Addon So That I Can Use Distribute It on Amazon Aws
How to Force a Range of Virtual Addresses
Sending Snmp2 Trap Message from Linux Command Lne
Compiling and Linking a 32 Bit Application on Debian 64 Bit
Sendmail/Procmail - Get Mail Sender and Mail Subject, Utf8 Encoding Issues