exec () любая команда в C - PullRequest
       9

exec () любая команда в C

8 голосов
/ 11 ноября 2011

Скажем, C, я хочу вызвать execvp() для любой строковой команды.Командой может быть просто:

char command[] = "ls -l";
char command[] = "rm *.txt";
char command[] = "cat makefile";

Я хочу поместить эту переменную команды в execvp().Таким образом, ароматизированная функция exec() может быть запущена любой произвольной командой.

Как я могу это сделать?Спасибо.

ПРИМЕЧАНИЕ: system() не допускается.

Ответы [ 5 ]

8 голосов
/ 11 ноября 2011

Если у вас есть для вызова execvp(), то вам нужно будет разделить эти строки на имя исполняемого файла и массив аргументов (первый - это «имя» программы, а последний - последний).является указателем NULL).

Это означает что-то вроде:

char cmd1[] = "ls";  char *args1[] = {"ls", "-l", NULL};
char cmd1[] = "rm";  char *args1[] = {"rm", "*.txt", NULL}; // but see
                                                            // globbing below.
char cmd1[] = "cat"; char *args1[] = {"cat", "makefile", NULL};

Это нетривиальное упражнение, особенно если вы хотите разрешить цитирование, глобирование, экранирование и так далее.

Цитирование означает, что вы должны быть осторожны с такими командами, как:

rm "file with spaces.txt"

, поскольку вы не можете просто разбивать пробелы - вам придется интерпретировать элементы в командетак же, как оболочка.Упрощенное разбиение на пробелы даст вам команду с тремя аргументами для этой строки, а не с правильным.

Под словом «глобализация» я подразумеваю, что у вас почти наверняка возникнут проблемы с чем-то вроде *.txt, поскольку обычно shell , который расширяет эти аргументы.Передача этого значения непосредственно в execvp() приведет к одиночному аргументу буквально *.txt, а не ко многим аргументам, совпадающим со всеми текстовыми файлами в вашем текущем каталоге.

Цитирование означает, что вы будетенужно обрабатывать такие вещи, как:

ls -l "file with spaces and \" quote in it"

, что еще больше усложнит ваш синтаксический анализатор.

Не поймите меня неправильно, это можно сделать, но это, вероятно, чертовски просто, просто используя system().

Если вы все еще думаете о маршруте execvp(), вам придется:

  • разбить строку на отдельные токены (довольно сложно, так как выдолжны обрабатывать кавычки и экранирование).
  • глобализировать все аргументы, что означает, что аргументы с подстановочными знаками в них (и только те, которые не экранированы или не защищены в силу нахождения внутри кавычек), расширяются в несколько аргументов.
  • построить массив аргументов с командой впереди и NULL в конце.
  • call execvp() с параметрами, являющимися первым элементом в этом массиве и адресом tон массив.
2 голосов
/ 11 ноября 2011

Чтобы использовать любую из функций в стиле execve, вам нужно самостоятельно проанализировать командную строку и построить вектор argv.Функции принимают символ **, где последний элемент равен нулю - вам нужно выделить достаточно памяти для всего этого.Тогда ваш вызов в стиле execve должен работать.

(ps. Вы ничего не упомянули о fork ...)

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

Нет, семейство функций exec не принимает одностроковую командную строку, как system.Вместо этого он использует argv -подобный массив строк:

char *command = "/path/to/command";
char *arguments[] = { "command", "first argument", "second argument", NULL };
execvp(command, arguments);

Обратите внимание, что первая запись в массиве arguments - это сама команда, и что массив заканчивается на NULL.

Вы проверили страницу руководства?

1 голос
/ 11 ноября 2011

Что вам нужно сделать, это заставить оболочку разобрать команду.Так что подумайте:

/bin/sh -c 'rm *.txt'

Это должно привести вас в правильном направлении.:)

1 голос
/ 11 ноября 2011

Для того, чтобы такие вещи, как "*" ">", "<", "&" и т. Д. Работали, вам нужно выполнить "/ bin / sh" и передать в командной строке в качестве аргументов. Итак, все сводится к токенизации вашей строки. </p>

...