Короткая программа ниже предназначена для перебора argv, переданного из командной строки, и выполнения каждого аргумента. Это не моя домашняя работа, это то, что я делаю, готовясь к выполнению своей домашней работы.
Первый аргумент получает входные данные от STDIN и STDOUT и записывает в конвейер. В конце каждой итерации (кроме последней) дескрипторы файлов меняются местами, так что канал, в который записано последнее выполнение, будет прочитан следующим. Таким образом, я намерен, например, для
./a.out /bin/pwd /usr/bin/wc
распечатать только длину рабочего каталога. Код следует за
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
main(int argc, char * argv[]) {
int i;
int left[2], right[2], nbytes; /* arrays for file descriptors */
/* pointers for swapping */
int (* temp);
int (* leftPipe) = left;
int (* rightPipe) = right;
pid_t childpid;
char readbuffer[80];
/* for the first iteration, leftPipe is STDIN */
leftPipe[0] = STDIN_FILENO;
leftPipe[1] = STDOUT_FILENO;
for (i = 1; i < argc; i++) {
/* reopen the right pipe (is this necessary?) */
pipe(rightPipe);
fprintf(stderr, "%d: %s\n", i, argv[i]);
fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
if ((childpid = fork()) == -1) {
perror("fork");
exit(1);
}
if (childpid == 0) {
/* read input from the left */
close(leftPipe[1]); /* close output */
dup2(leftPipe[0], STDIN_FILENO);
close(leftPipe[0]); /* is this necessary? A tutorial seemed to be doing this */
/* write output to the right */
close(rightPipe[0]); /* close input */
dup2(rightPipe[1], STDOUT_FILENO);
close(rightPipe[1]);
execl(argv[i], argv[i], NULL);
exit(0);
}
wait();
/* on all but the last iteration, swap the pipes */
if (i + 1 < argc) {
/* swap the pipes */
fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
temp = leftPipe;
leftPipe = rightPipe;
rightPipe = temp;
fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
}
}
/* read what was last written to the right pipe */
close(rightPipe[1]); /* the receiving process closes 1 */
nbytes = read(rightPipe[0], readbuffer, sizeof(readbuffer));
readbuffer[nbytes] = 0;
fprintf(stderr, "Received string: %s\n", readbuffer);
return 0;
}
ОБНОВЛЕНИЕ : во всех нижеприведенных тестовых примерах я изначально использовал / bin / wc, но который показал, что туалет находится совсем не там, где я думал. Я исправляю результаты.
Результат в тривиальном случае (./a.out / bin / pwd) такой, как ожидалось:
1: /bin/pwd
Received string: /home/zeigfreid/Works/programmatical/Langara/spring_2012/OS/labs/lab02/play
Результат выполнения этой программы с первым примером (./a.out / bin / pwd / usr / bin / wc):
1: /bin/pwd
0 1 3 4
3 4 0 1
2: /bin/wc
В этот момент терминал зависает (возможно, ожидает ввода).
Как видите, строка не получена. Я полагаю, что я сделал что-то неправильно выше, либо при замене указателей, либо что я не понимаю дескрипторы файлов unix. Моим заданием, в конце концов, будет интерпретация труб произвольной длины, и это одна из моих идей для решения проблемы.Мне сложно понять, правильно ли я нахожусь на верном пути, чтобы лаять на дерево. Я понимаю файловые дескрипторы unix?
ОБНОВЛЕНИЕ:
Запустив его с / bin / ls в качестве второго аргумента, я получил следующий результат (числа - это дескрипторы файлов в разных точках):
1: /bin/pwd
0 1 3 4
0 1 3 4
3 4 0 1
2: /bin/ls
3 4 5 6
Received string: a.out
log
pipe2.c
play.c
@
В конце все еще есть мусор, но теперь меня больше беспокоит то, что я не понимаю указатели! Однако эти две команды независимы друг от друга, они на самом деле не используют канал.
ОБНОВЛЕНИЕ : символ мусора возник из-за того, что строка не закрывалась. Сейчас закрываю, а фигня нет.