I have a C program which looks like this:
#include <stdio.h>
#include <unistd.h>
int main()
{
int n;
char str[16];
scanf("%d", &n);
printf("n: %d\n", n);
int count = read(STDIN_FILENO, str, 16);
printf("str: %s\n", str);
printf("read %d bytes\n", count);
}
If I pipe data into this program using a command like
(echo -en '45\n'; echo -en 'text\n') | ./program
only scanf()
actually reads data. read()
simply reads 0 bytes.
In other words, the program outputs
n: 45 str: read 0 bytes
How can I pipe data to both scanf()
and read()
?
Edit: Sorry, I should have clarified: I'm looking for a way to do this without modifying the source. Thanks to the people who answered and commented anyway.
When a user process attempts to read from an empty pipe (or FIFO), the following happens: If one end of the pipe is closed, 0 is returned, indicating the end of the file. If the write side of the FIFO has closed, read(2) returns 0 to indicate the end of the file.
Do (f)gets and sscanf from that? @PeterSchneider there's nothing that you can do with scanf() and not with fgets() . The only difference is that scanf() is hard to use correctly and it's hazardous.
pipe() is a system call that facilitates inter-process communication. It opens a pipe, which is an area of main memory that is treated as a "virtual file". The pipe can be used by the creating process, as well as all its child processes, for reading and writing.
pipe() is a Linux system function. The pipe() system function is used to open file descriptors, which are used to communicate between different Linux processes. In short, the pipe() function is used for inter-process communication in Linux.
#include <stdio.h>
#include <unistd.h>
int main()
{
int n;
char str[16];
setbuf(stdin, NULL); // Ensure that there's no buffering for stdin
scanf("%d", &n);
printf("n: %d\n", n);
int count = read(STDIN_FILENO, str, 16);
printf("str: %s\n", str);
printf("read %d bytes\n", count);
}
As the previous answers said, scanf is causing your problem because it uses a buffer. So you can make sure it doesn't by callingsetbuf(stdin,NULL)
.
It is not recommended at all to use both file descriptor functions (read) and stream functions (scanf) for the same file descriptor. Functions using FILE *
(i.e. fread/fprintf/scanf/...) are buffering data while functions using file descriptors (i.e. read/write/...
) do not use those buffers. In your case, the easiest way to fix the program is to use fread
instead of read
. The program may look like:
#include <stdio.h>
#include <unistd.h>
int main() {
int n;
char str[16];
scanf("%d", &n);
printf("n: %d\n", n);
int count = fread(str, 16, 1, stdin);
printf("str: %s\n", str);
printf("read %d bytes\n", count);
}
In your original example, scanf
has read the input ahead and stored it in its buffer. Because the input was so short and was available immediately it was entirely read to the buffer and your invocation of read
had nothing more to read.
This does not happen when you enter the input directly from a terminal, because scanf
does not buffer data beyond one line when reading from a terminal device. This would also not happen if you create a time pause in your piped input for example by a command:
(echo -en '45\n'; sleep 1; echo -en 'text\n') | ./program
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With