Попытался написать небольшой пример на С. Кажется, я что-то делаю неправильно...
Вот пример. В примере пытаюсь запустить дочерним процессом "ps" и перехватить его вывод. Пайпы использовал здесь потому, что в реальной задаче нужно перенаправлять и поток вывода и поток ошибок нескольких процессов. В данном примере только один процесс и перенаправление только одного потока вывода.
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
const char * const Child_Str = "ps";
int main (int argc, char **argv)
{
printf("Test 04-000-0000\n");
pid_t pid;
int opipe[2];
if (-1 == pipe(opipe))
{
printf("Error: creating pipe");
return -1;
}
//-----------------------------------------------------------------------
// Create a child process
pid = fork();
switch (pid)
{
case -1:
printf("Error: fork()\n");
return -1;
case 0:
close(opipe[1]);
break;
default:
// redirect the standard output to the pipe
close(1);
dup2(opipe[1], 1);
close(opipe[0]);
close(opipe[1]);
// run the child process
printf("run child process\n\n");
execlp(Child_Str, Child_Str, 0);
printf("Error: run %s\n", Child_Str);
break;
}
//-----------------------------------------------------------------------
// Catch the output
const time_t t = time(0);
fd_set pipesfd;
fd_set readset;
char buffer[1025];
FD_ZERO(&pipesfd);
FD_SET(opipe[0], &pipesfd);
printf("Start the redirecting.\n");
// Timeout is 10 sec
while (10 > time(0) - t)
{
readset = pipesfd;
// select() timeout is 1 sec.
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
int retval = select(1, &readset, 0, 0, &tv);
if (-1 == retval)
{
printf("Error: select()");
return -1;
}
if (retval)
{
printf("Data is available now.\n");
// FD_ISSET(opipe[0], &readset) will be true.
int readed = read(opipe[0], buffer, 1024);
if (0 < readed)
{
printf("===> Good select() result\n");
buffer[readed] = 0;
printf("--> %s", buffer);
}
else
{
FD_CLR(opipe[0], &readset);
printf("Close the input pipe.");
}
}
else
{
printf("Error: No data within timeout.\n");
int readed = read(opipe[0], buffer, 1024);
if (0 < readed)
{
printf("===> select() error ???\n");
buffer[readed] = 0;
printf("--> %s", buffer);
}
}
}
close(opipe[0]);
printf("Elapsed time: %d\n", time(0) - t);
return 0;
}
Вот, что получается в результате:
testuser@ws6~$ ./a.out
Test 04-000-0000
testuser@ws6:~$
Start the redirecting.
Error: No data within timeout.
===> select() error ???
--> run child process
PID TTY TIME CMD
15918 pts/0 00:00:00 bash
5963 pts/0 00:00:00 make
6770 pts/0 00:00:00 ps
6771 pts/0 00:00:00 test_04_000_000
Error: No data within timeout.
Error: No data within timeout.
Error: No data within timeout.
Error: No data within timeout.
Error: No data within timeout.
Error: No data within timeout.
Error: No data within timeout.
Error: No data within timeout.
Error: No data within timeout.
Elapsed time: 10
Два момента:
1. Как я понимаю, если в pipe что-то есть, то программа должна пойти по ветке "Data is available now". Вместо этого программа пошла по ветке "Error: No data within timeout", но принудительное чтение из пайпа показывает, что там всё-таки есть данные... Почему?
2. После запуска программы a.out почти сразу вернулось управление в shell, как будто я выполнил "a.out &". Это побочный эффект вызова fork()?
Что я здесь делаю неправильно?