Реализация каналов в Linux Shell с C - PullRequest
1 голос
/ 26 ноября 2011

Я пытаюсь реализовать простую программу оболочки, которая поддерживает несколько трубопроводов. На данный момент моя оболочка может реализовывать несколько простых встроенных команд, а также внешние команды. Я сделал это, получив пользовательский ввод из командной строки, разделенной пробелом " ", и поместил каждую строку в char* argv[]. Проблема сейчас заключается в выполнении труб. Я прочитал немного об этом в этой ссылке http://www.cs.loyola.edu/~jglenn/702/S2005/Examples/dup2.html. И я понял, как это работает.

Итак, я думал о strcmp каждый argv[i] с "|", и когда я встречаю трубку, я fork новый процесс. Затем я помещаю строки перед трубой в char* argv[], а строку после трубы в другую char* argv[]. Это может работать для 1 канала, но если пользователь ввел несколько каналов с несколькими каналами, этот метод может стать утомительным. Моя главная проблема заключается в разделении струн на обоих концах труб. Любые идеи о том, как я могу это реализовать? Спасибо.

Ответы [ 2 ]

2 голосов
/ 26 ноября 2011

Возможно, вы даже можете просто повторно использовать массив argv, заменив каналы пустой строкой (которая завершает массив argv).

Итак, ваш массив был примерно таким:

"a", "b", "|",  "c", "d", "e", "|",  "f", "g", "h", NULL

который вы меняете на

"a", "b", NULL, "c", "d", "e", NULL, "f", "g", "h", NULL

и вуаля, вот ваши три командные строки: argv, argv+3, argv+7

Трудная часть с конвейерами - это настройка файловых дескрипторов stdin и stdout, а не фактическое выполнение команд.

2 голосов
/ 26 ноября 2011

Разделить и завоевать:

  1. Найти первый аргумент канала
  2. Если канал не найден, выполнить массив с выводом stdout и завершить.
  3. Разделитьмассив аргументов между первой частью, не относящейся к трубе, и остальными.
  4. Создайте канал и выполните первую часть, не относящуюся к трубе, с каналом в качестве вывода
  5. Удалите первую часть без трубы иканалы из массива аргументов
  6. Перейти к 1

Шаг 3 из-за семантики массива C довольно прост:

char **arguments;
int pipe_position = /* for example: */ 5;
assert( strcmp( arguments[pipe_position], "|" ) == 0 );
arguments[pipe_position] = NULL;
char **my_arguments = arguments;
arguments = arguments + pipe_position + 1;

, а затем my_arguments - этомассив длиной pipe_position, содержащий первые аргументы, а arguments - массив длиной argc - pipe_position - 1, содержащий остальные.Вы можете дать эти указатели execvp без проблем.Да, они указывают на один и тот же блок памяти, но это не касается execvp.

...