I hope to see the output of the command executed by popen
as soon as possible.So I change the buffering type of the file stream returned by popen
to line buffered. As per the document, setvbuf
seems work for this goal. I did a simple test on Ubuntu16.4
, it does not make any difference indeed.
Here is the code snippet which I used to do the said test:
#include <stdio.h>
#include <string.h>
int main(void)
{
char buffer[1024];
memset(buffer, 0, 1024);
FILE* file = popen("bash -c \"for i in 1 2 3 4 5;do echo -e -n 'thanks a lot\n'; sleep 1; done\" ", "r");
if(NULL != file)
{
int size;
printf("setvbuf returns %d\n", setvbuf(file, NULL, _IOLBF, 0));
while((size = fread(buffer, 1, 1024, file))>0)
{
printf("size=%d\n", size);
memset(buffer, 0, 1024);
}
}
return 0;
}
Here is the output of the code snippet which runs on Ubuntu16.04
:
setvbuf returns 0
//about five seconds later
size=65
As per the document, which says that:
The function setvbuf() returns 0 on success.
As per the output above, setvbuf(file, NULL, _IOLBF, 0)
has successfully set the buffing type of file
returned by popen
to line buffered.But the output of the aforementioned code snippet indicates it still uses the default block buffered.
But when I tried getline
, it could achieve the goal, which is really out of my expectation.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE* file = popen("bash -c \"for i in 1 2 3 4 5;do echo -e -n 'thanks a lot\n'; sleep 1; done\" ", "r");
char* line=NULL;
size_t len;
if(NULL != file)
{
// std::cout << setvbuf(file, NULL, _IOLBF, 0) << std::endl; //setvbuf has not been called
while(getline(&line, &len, file)>0)
{
printf("strlen(line)=%lu\n", strlen(line));
free(line);
line = NULL;
}
}
free(line);
return 0;
}
Here is the output:
//one second later
strlen(line)=13
//one second later
strlen(line)=13
//one second later
strlen(line)=13
//one second later
strlen(line)=13
//one second later
strlen(line)=13
I am really conscious about why getline
could acquire the output of the pipe as soon as possible, whereas setvbuf
& fread
does not work.
CodePudding user response:
getline
stops reading once it gets to a newline. fread
keeps reading until it reads as much data as you specified (in your case, 1024 bytes) or it encounters EOF or an error. This has nothing to do with buffering. You might want to look at read
to see if it's closer to what you want.
CodePudding user response:
@Jeremy Friesner'answer:
In my experience, the call to setvbuf(stdout, NULL, _IONBF, 0) needs to be executed inside the child process in order to get the behavior you want. (Of course that's much easier to achive if the child process's executable is one you control rather than /bin/bash). popen() in the parent process can't give you data that the child process hasn't supplied to it yet.