As suggested in the comments below you could do:
{ echo a & sleep 0.1; echo b; } | ./main
Notice that you may have to adjust amount of time to sleep. The point of
this command is to make the first invocation of read() think that a
is the entire input it got. The assumption is that the C program
will reach the second read() after echo a &
(note the &
- it's
sent to the background) has already finished and was processed by the
first read(). But since Linux is a multi-user true multitasking OS
which additionally performs lazy virtual memory allocation sleep 0.1
may not be enough in all cases for this assumption to work.
The reason it works and
{ echo a && echo b; } | ./main
doses not is that read() reads the entire available stdin up to SIZE
characters the first time it's read, leaving no character to be read
for the second time. If you checked the value read() returns:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#define SIZE 0x100
int main(void)
{
char buffer1[SIZE];
char buffer2[SIZE];
printf("Enter first line of input: \n");
ssize_t read_bytes = read(STDIN_FILENO, buffer1, SIZE);
buffer1[read_bytes] = '\0';
printf("First input - count of read bytes: %jd\n", (intmax_t) read_bytes);
printf("Enter second line of input: \n");
read_bytes = read(STDIN_FILENO, buffer2, SIZE);
printf("Second input - count of read bytes: %jd\n", (intmax_t) read_bytes);
buffer2[read_bytes] = '\0';
printf("\nFirst input:\n%s", buffer1);
printf("\nSecond input:\n%s", buffer2);
return 0;
}
you'd see that it doesn't read any character the second time:
$ ./main << EOF
1
2
EOF
Enter first line of input:
First input - count of read bytes: 4
First input:
1
2
Enter second line of input:
Second input - count of read bytes: 0
Second input:
First input:
1
2
Second input:
To make { echo a && echo b; } | ./main
work you'd have to either switch to
getline() or save both inputs to a single buffer and use strtok() to parse the buffer by newlines. getline()
version could look like this:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
size_t size = 0x100;
char *buffer1 = malloc(size);
if (buffer1 == NULL)
{
perror("malloc");
}
char *buffer2 = malloc(size);
if (buffer2 == NULL)
{
perror("malloc");
}
printf("Enter first line of input: \n");
getline(&buffer1, &size, stdin);
printf("Enter second line of input: \n");
getline(&buffer2, &size, stdin);
printf("\nFirst input:\n%s", buffer1);
printf("\nSecond input:\n%s", buffer2);
free(buffer1);
free(buffer2);
return 0;
}
Example:
$ ./main << EOF
1
2
EOF
Enter first line of input:
Enter second line of input:
First input:
1
Second input:
2
There are 3 more points I'd like to discuss here:
you don't need fflush(stdout);
because stdout is
always flushed after a newline
you don't need to lookup for man pages on the Internet because you
have them locally - just type man 2 read
in the terminal or open
them inside your editor (Emacs for example can do that)
you have a bug in the code you posted in your question - read()
does not add nul bytes automatically, you have to do it yourself to
avoid UB. It should be:
printf("Enter first line of input: \n");
ssize_t read_bytes = read(STDIN_FILENO, buffer1, SIZE - 1);
buffer1[read_bytes] = '\0';
SIZE
"? (Maybe it's just me, but I'm unable to parse "must sometimes" in this context).read()
isn't an acceptable solution.