С файлом z2, содержащим:
user1:x:1001:1001::/home/user1home:/bin/bash
user2:x:1002:1002::/home/user2home:/bin/bash
user3:x:1003:1003::/home/user3home:/bin/bash
user4:x:1004:1004::/home/user4home:/bin/bash first
user1:x:1001:1001::/home/user1home:/bin/bash
user2:x:1002:1002::/home/user2home:/bin/bash
user3:x:1003:1003::/home/user3home:/bin/bash
user4:x:1004:1004::/home/user4home:/bin/bash second
Утилита cgrep
выдаст:
$ cgrep -e '1002:1002' +w '/home/user4home' z2
========================================
user2:x:1002:1002::/home/user2home:/bin/bash
user3:x:1003:1003::/home/user3home:/bin/bash
user4:x:1004:1004::/home/user4home:/bin/bash first
========================================
user2:x:1002:1002::/home/user2home:/bin/bash
user3:x:1003:1003::/home/user3home:/bin/bash
user4:x:1004:1004::/home/user4home:/bin/bash second
Дополнительная информация оcgrep
(контексте, оконном grep):
cgrep shows context of matching patterns found in files (man)
Path : ~/executable/cgrep
Version : 8.15
Type : ELF 64-bit LSB executable, x86-64, version 1 (SYS...)
Home : http://sourceforge.net/projects/cgrep/ (doc)
С наилучшими пожеланиями... ура, дрл
У вас есть:
waitpid(cmd_pid,NULL,WNOHANG);
Включая опцию WNOHANG
, вы говорите waitpid()
не ждать завершения процесса, если он еще не завершен.
Я предполагаю, что вы добавили это, потому что ваша программа зависнет, если вы ее не включите. Это связано с тем, что первоначальный родитель по-прежнему имеет открытый дескриптор файла для записи -конца канала, поэтому процесс чтения по-прежнему заблокирован в ожидании ввода данных в этом канале.
Вот исправленная версия вашей программы, которая закрывает дескрипторы файлов каналов и не использует WNOHANG
.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
if (argc <= 1) {
printf("ERROR: No arguments passed\n");
printf("USAGE:./pipe <command 1> | <command 2>\n");
return 1;
}
char *cmd1[50];
char *cmd2[50];
int cmd1_arg = 0;
int cmd2_arg = 0;
int pipe_num = 0;
for (int cla = 1; cla < argc; cla++) {
if (!strcmp(argv[cla], "|")) {
pipe_num++;
} else if (pipe_num == 0) {
cmd1[cmd1_arg++] = argv[cla];
} else if (pipe_num == 1) {
cmd2[cmd2_arg++] = argv[cla];
}
}
cmd1[cmd1_arg] = NULL;
cmd2[cmd2_arg] = NULL;
if (pipe_num != 1) {
printf("ERROR: Insufficient arguments passed\n");
printf("USAGE:./pipe <command 1> | <command 2>\n");
return 1;
}
int pipe_fd[2];
if (pipe(pipe_fd) < 0) {
perror("pipe");
return 1;
}
const pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
} else if (pid != 0) {
const pid_t cmd_pid = fork();
if (cmd_pid < 0) {
perror("fork");
return 1;
} else if (cmd_pid != 0) {
printf("PARENT PID %d\n", getpid());
close(pipe_fd[0]);
close(pipe_fd[1]);
if (waitpid(pid, NULL, 0) < 0) {
perror("waitpid");
}
if (waitpid(cmd_pid, NULL, 0) < 0) {
perror("waitpid");
}
} else {
printf("c2 PID %d\n", getpid());
if (dup2(pipe_fd[0], STDIN_FILENO) < 0) {
perror("dup2");
return 1;
}
close(pipe_fd[0]);
close(pipe_fd[1]);
if (execvp(cmd2[0], cmd2) < 0) {
perror("CMD2 FAIL");
return 1;
}
}
} else {
printf("c1 PID %d\n", getpid());
if (dup2(pipe_fd[1], STDOUT_FILENO) < 0) {
perror("dup2");
return 1;
}
close(pipe_fd[0]);
close(pipe_fd[1]);
if (execvp(cmd1[0], cmd1) < 0) {
perror("CMD1 FAIL");
return 1;
}
}
return 0;
}
Запуск этой программы дает мне:
./a.out echo 1 2 3 '|' wc
PARENT PID 20412
c1 PID 20413
c2 PID 20414
1 3 6
$
Ваш исходный процесс, родительский для дочерних процессов, запускает это:
waitpid(pid,NULL,0);
waitpid(cmd_pid,NULL,WNOHANG);
printf("PARENT PID %d\n",getpid());
То есть он ожидает выхода первого потомка, делает системный вызов, чтобы проверить, вышел ли второй, но из-за WNOHANG
на самом деле не ждет этого. В любом случае проверка спорна, так как программа не использует возвращаемое значение из waitpid()
. Затем родитель печатает свой PID и продолжает работу по функции через два других оператораif
-и выходит через return 0
.
В этот момент второй дочерний процесс может быть все еще запущен, а может и нет. Без явной синхронизации нет никаких гарантий того, в каком порядке происходят события. Кроме того, оболочка не знает о дочерних процессах, запускаемых вашей программой, и не имеет механизма их ожидания. Основной процесс должен wait*()
для них.
Прежде чем продолжить работу с кодом, избавьтесь от беспорядка вложенных операторов if -и создайте более четкую структуру. Обычный способ упростить подобный код состоит в том, чтобы дочерние процессы немедленно вызывали функцию и _exit()
там или сразу после возврата функции. Прямо сейчас, если ваши вызовы exec*()
терпят неудачу, дочерние процессы также продолжают выполнение того же кода вместо выхода.