С++ - сценарий Linux/shell запускает дочерние процессы и получает их статусы возврата

Я ищу решение для написания части программы на С++ в Linux, которая анализирует файл, содержащий программы с заданными аргументами, а затем запускает эти программы с их аргументами аргументов.

Каждая программа (строка) выполняется по одной, а затем родительский процесс ожидает выхода каждого дочернего элемента и проверяет его статус выхода (мне интересно, только если он равен 0).

Пример текста для разбора:

prog1 -a arg1 -m arg2 -c arg3 prog2 arg1 arg2 arg3 arg4 ....

Я считаю, что лучше всего хранить все в векторе строк, например:

vector <std::string> p_vector;
while (getline(file, line))
    p_vector.push_back(line);

затем для каждого элемента i от 0 до p_vector.size() мне нужно сделать что-то вроде примера, который я нашел в сети:

if(fork() = 0) //? shouldn't here be == ?
{
    execv(fullpath,argv);//does full path mean my p_vector[i]? or the child process and then argv is a list of space delimited arguments?
    exit(1);
}
else
{
    int *status;
    wait(status);
    if(*status == 0)
    printf("%s exited correctly", fullpath);//fullpath, right?
    else
    //other printf error
}

или, мне лучше использовать для этого

string command = p_vector[i]; // eg: ls -l -a -l folder_one , put more arguments because I do not know the exact number of them for each parsed line

int exitCode = system(command.c_str());

Если у кого-то также есть идея, как это сделать с помощью скрипта, это тоже будет приветствоваться, хотя областью моего вопроса является C++!

Я мог бы использовать QProcess Qt, поскольку я знаю, как его использовать, но это может вызвать некоторые юридические проблемы, о которых я сейчас знаю (однако нет проблем с обменом кодом, компания, в которой я работаю, может не разрешить это)

Спасибо и с нетерпением жду ответов от вас!


person Johnny    schedule 31.07.2011    source источник
comment
Где вы нашли этот ужасный, ужасный пример?   -  person Ignacio Vazquez-Abrams    schedule 31.07.2011
comment
да, должно быть ==   -  person unkulunkulu    schedule 31.07.2011
comment
Я нашел этот пример на tek-tips.com/viewthread.cfm?qid =771930&page=17 . Это выглядело подозрительно, но я должен сделать это к завтрашнему утру, и у меня нет ничего, чтобы проверить это прямо сейчас (ПК с Linux)   -  person Johnny    schedule 31.07.2011


Ответы (3)


Я согласен с Игнасио. Но если вам нужно это сделать, я бы предпочел, чтобы вы использовали команду System/popen.

НО УБЕДИТЕСЬ, ЧТО ВЫ НЕ ИСПОЛЬЗУЕТЕ НИКАКОЙ КОМАНДЫ, КОТОРАЯ БУДЕТ ДОСТАВЛЯТЬ ВАМ ПРОБЛЕМЫ... например, "rm -rf *".

Это очень вероятно, если вы собираетесь читать из файла, которому нельзя доверять.

И не нужно копировать его в новую строку, вы можете сделать "system(p_vector[i].c_str());"

person Arunmu    schedule 31.07.2011
comment
Нет, я не буду этого делать. Все программы на самом деле являются тестами, написанными мной, которые отправляют некоторые сообщения CAN и обрабатывают ответы в функциях обратного вызова. Мне нужно что-то сделать, чтобы автоматизировать процесс и просто быть в курсе тех, которые терпят неудачу. Никакой среды не нужно настраивать. - person Johnny; 31.07.2011
comment
Окей :) . Тогда вперед. Надеюсь, производительность этого для вас не имеет значения, потому что, если есть много команд, которые необходимо выполнить, то для каждой команды вы создаете новый процесс [либо вручную, либо с помощью system/popen], что является дорогостоящей операцией. - person Arunmu; 31.07.2011
comment
Ну, производительность может быть важна. Я думаю, что я буду придерживаться системы. Мне все еще нужно выполнять по одному процессу за раз, поэтому я думаю, что мне следует использовать что-то вроде while (exitCode != 0 || exitCode != -1) //мои значения по умолчанию для pass & fail sleep (variableDelay); // не занимать больше ресурсов, пока процесс не завершится, верно? - person Johnny; 31.07.2011
comment
Когда вы получаете код выхода из системной команды, это означает, что процесс завершил выполнение [а как еще вы могли бы получить код выхода :)]. Тебе не нужно спать. - person Arunmu; 31.07.2011
comment
@Johnny: В таком случае, что не так с make? Вы проводите кучу тестов. make делает это очень хорошо. - person David Hammen; 31.07.2011
comment
@ArunMu, ты прав, мой вопрос о сне был совершенно глупым, я был увлечен асинхронными вещами, которые для меня в новинку, и я думал о чем-то другом. Спасибо! - person Johnny; 31.07.2011

в баш:

echo file | while read command
do
   eval $command
done

где file — файл, содержащий для каждой строки программу с ее аргументами

person Manlio    schedule 31.07.2011
comment
Это выглядит красиво, как мне интерпретировать статус выхода? Должен ли я использовать что-то вроде if ($? == 0) echo right или... - person Johnny; 31.07.2011
comment
да $? даст вам статус выхода последней команды запуска. если [$? -экв 0 ] ; затем эхо да ; фи - person Arunmu; 31.07.2011
comment
сценарий, предоставленный Saphrosit, будет достаточным для вашего требования, если у вас нет особых требований к тому, чтобы код был на С++ - person Arunmu; 31.07.2011
comment
Я считаю, что оба хороши и в порядке. - person Johnny; 31.07.2011

Чтобы использовать семейство exec, вам нужно разобрать p_vector[i] на токены. Нулевой токен идентифицирует программу, которую нужно выполнить; остальные задают аргументы программе. execvp эмулирует то, что делает ваша оболочка: она ищет программу в пути поиска. execv ожидает, что вы сделаете еще один шаг вперед. Вам нужно указать путь к программе, но не обязательно полный путь; относительные пути работают нормально. Еще одна маленькая хитрость в отношении exec: нулевой аргумент должен быть копией имени программы. В этом случае много работы.

По сути, system делает следующее:

int pid, status, wait_pid;
char * shell;

shell = getenv ("SHELL");
if (shell == 0) {
   // Deal with missing SHELL environment variable problem
   return -1;
}

pid = fork();
if (pid < 0) {
    return -1;
}

else if (pid == 0) {
   execl (shell, shell, string_to_execute);
   return -1;
}

waited_pid = waitpid (pid, &status, wait_options);
if (waited_pid != pid) {
   return -1;
}

return status;

Другими словами, почти то, что вы хотите.

Редактировать 1
Одна проблема с system: это небезопасно, так как все выходят. АрунМу уже упоминал rm -rf /. Что делать, если какая-то строка содержит do_something_benign; rm -rf / Если вы можете доверять содержимому файла, использование system нормально. Если нет, гораздо лучше использовать что-то вроде perl или другого языка сценариев, который можно заставить работать в безопасном режиме.

Редактировать 2
Учитывая комментарии, что побудило вас написать это на C или C++? Язык сценариев или, что еще лучше, цель test в вашем make-файле лучше подходят для решения этой проблемы.

person David Hammen    schedule 31.07.2011
comment
Спасибо за быстрый ответ! Нет проблем с безопасностью. Я могу доверять содержанию. программы, которые должны быть выполнены, уже находятся в /usr/bin, поэтому я считаю, что проблем с путями быть не должно. Таким образом, string_to_execute, который вы использовали, — это полная строка из вектора, разбиение не требуется, верно? - person Johnny; 31.07.2011
comment
Ну и то, что я не уверен, какой тип (c или script) предпочтет клиент. Кроме того, мне может быть разрешено или не разрешено делиться окончательным кодом. - person Johnny; 31.07.2011