Reputation: 397
I have a simple C file, that writes to the standard output using printf
and write(1,..)
functions.
File: main.c
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("Hello\n");
printf("Mars\n");
fsync(1);
write(1,"Ola\n",4);
write(1,"Earth\n",6);
}
> gcc main.c -o test
When I redirect the output to a file, I see different order than the output in the terminal. It seems, that when I am using redirection write(..)
writes before than printf(..)
, even tough, printf()
is earlier in code and there is a fsync(..)
in between.
Is there some variant of the redirection operator that will ensure order, or am I doing something wrong.
Output in terminal:
> ./test
Hello
Mars
Ola
Earth
Output in out
file:
> ./test >out
# or ./test|tee out
> cat out
Ola
Earth
Hello
Mars
Upvotes: 1
Views: 161
Reputation: 224052
printf
writes to the C stream stdout
, which is buffered by the C standard library routines and ultimately written to Unix file descriptor 1.
fsync
and write
operate on Unix file descriptor 1. fsync
flushes data from file descriptor 1, but it has no effect on the buffers of the streams of the C standard library.
The C standard library I/O routines operate differently depending on whether standard output is going to a terminal or to a file. This is detected during program start-up. When output is going to a terminal, it is deemed important to get it to the user, and the buffer is flushed when \n
is written to a stream. This is called line buffered, and output to a terminal is set to line buffered by default.
When output is going to a file, it is not deemed important to flush it promptly, since a user is not expected to see it right away and performance is better if output is fully buffered. So the buffer is flushed only when it is full, the stream is closed, or an explicit flush request is made. This is called fully buffered, and output to a file is set to fully buffered by default.
This is generally addressed in C 2018 7.21.3, in which paragraph 7 says:
… 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.
(When the output is a terminal, the C implementation may also use unbuffered mode instead of line buffered, in which case all characters are sent to the terminal as soon as they are written. This is uncommon.)
You can explicitly requesting flushing of stdout
with fflush(stdout)
.
After stdout
is opened but before any other operation is performed on it, you can change its buffer method with setvbuf(stdout, NULL, mode, 0)
, where mode
is _IOFBF
, _IOLBF
, or _IONBF
for full, line, or no buffering, respectively. (You can also pass a char
array and its size in place of NULL
and 0
, and the library will use that array for the buffer, after which you should not use the array for any other purpose. If you pass NULL
and a size, the library may use that size to perform its own buffer allocation, but that is not guaranteed.) setvbuf
returns an int
that may be non-zero if it cannot honor the request.
Upvotes: 4
Reputation: 67
have a look at the dup2 system call: https://www.geeksforgeeks.org/dup-dup2-linux-system-call/
you can redirect stdoutput / input to a file
Upvotes: -1