Linux, как создать дочерний процесс, используя параметр из argv [] в C

Я хочу создать программу msh, которая будет распознавать некоторые другие написанные мной программы на C, создавать новый процесс для этой программы на C и запускать ее.

Например, я уже написал свои собственные функции копирования, перемещения и удаления с именами mycopy, myremove и mymove.

Я хочу иметь возможность сделать ./msh mycopy file1 file2 И заставить msh создать новый процесс, запустить mycopy и выполнить действие, а перед выходом дождаться завершения этого дочернего процесса.

Я попробовал то, что вы видите ниже, и он компилируется, но, похоже, не выполняет задачи. Какие-либо предложения? Я никогда раньше не использовал fork(), execl() или wait(), поэтому, возможно, я пропустил и включил или параметр, пожалуйста, поправьте меня, если я ошибаюсь.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char* argv[]){

int pid;

if(strcmp(argv[1], "mycopy") == 0){
    if(pid = fork() == 0){
        execl("/home/1234/mycopy", argv[2], argv[3]);
    }
}

if(strcmp(argv[1], "myremove") == 0){
    if(pid = fork() == 0){
        execl("/home/1234/myremove", argv[2]);
    }
}

if(strcmp(argv[1], "mymove") == 0){
    if(pid = fork() == 0){
        execl("/home/1234/mymove", argv[2], argv[3]);
    }
}

if(pid > 0){
    wait((int*)0);
}

return 0;
}

Я пробовал это и работал 3, напечатанный дважды. Означает ли это, что моя команда execl не работает, и если да, то как мне ее исправить, поскольку argv[2] и argv[3] необходимо передать в ./mycopy

    int pid = fork();
    if(strcmp(argv[1], "mycopy") == 0){
            if(pid  == 0){
                    printf("WORKING1");
                    execl("/home/1234/mycopy", argv[2], argv[3]);
                    printf("WORKING2");
            }
    }
     wait((int*)0);
    printf("WORKING3");
    return 0;

person Mkey    schedule 19.11.2015    source источник
comment
Вам нужно научиться делать отступы в коде. Также посмотрите на функцию strcmp, вы не можете сравнивать строки, используя == в C   -  person TheQAGuy    schedule 19.11.2015
comment
Хорошо, я только что реализовал ваше предложение, теперь кажется, что мой терминал завис. Вы видите какие-либо проблемы с моей командой ожидания?   -  person Mkey    schedule 19.11.2015
comment
Возможный дубликат Выполнение команды с помощью execvp   -  person PSkocik    schedule 19.11.2015
comment
Если вы используете strcmp, вам нужно добавить #include<string.h>   -  person TheQAGuy    schedule 19.11.2015
comment
Спасибо, я только что включил это, но мне все еще не повезло заставить его работать.   -  person Mkey    schedule 19.11.2015
comment
Я не уверен, сколько вы уже исправили. Но большая проблема в вашем текущем редактировании заключается в том, что вам нужно добавить NULL в качестве последнего аргумента в ваш список execl(): Как вызвать execl() в C с правильными аргументами?. ДРУГИЕ ПРЕДЛОЖЕНИЯ: 1) Проверьте наличие argc >= 2, 2) Добавьте fprintf(stderr, "I got this far\n") отладочных stmts в основную и дочернюю программы, чтобы увидеть, как далеко они продвинулись, 3) Добавьте fprintf(stderr, "pid=%d\n, pid) отладочных stmts   -  person paulsm4    schedule 19.11.2015
comment
Только что попробовал и все равно ничего   -  person Mkey    schedule 19.11.2015
comment
Я помещаю операторы printf во все части, и они выполняются, как и ожидалось, но, как вы сказали, что-то не так с моим execl   -  person Mkey    schedule 19.11.2015
comment
Поскольку argv[2] и argv[3] используются в программе mycopy   -  person Mkey    schedule 19.11.2015
comment
И я не думаю, что execl принимает более 3 параметров.   -  person Mkey    schedule 19.11.2015
comment
execl() — это функция с переменным числом аргументов, что означает, что она принимает столько аргументов, сколько вы ей указываете, как и printf(). Первым аргументом execl() является имя загружаемого исполняемого файла, а его второй аргумент становится первым аргументом (argv[0]) нового процесса.   -  person Darwin von Corax    schedule 19.11.2015
comment
Ваши правки означают, что некоторые ответы теперь не имеют смысла. Ваш исходный код не проверял возвращаемое значение fork(), чтобы выяснить, было ли оно дочерним или родительским, поэтому ответы, указывающие на это, теперь не синхронизированы с вопросом. Вопрос уже малопонятен. У него просто есть ошибка, когда список аргументов не завершается NULL до execl. Прочтите справочную страницу.   -  person Peter Cordes    schedule 19.11.2015
comment
Кроме того, ваша обертка должна разветвляться? Разве вы не можете просто выполнить exec, так как вы просто возвращаетесь после wait()ing для дочернего элемента.   -  person Peter Cordes    schedule 19.11.2015


Ответы (1)


Форкинг всегда кажется чем-то вроде головокружения для новичков. На самом деле происходит следующее: когда вы возвращаетесь из fork(), у вас теперь есть два процесса (родительский и дочерний), оба только что вернулись из fork() и оба из которых собираются выполнить следующую инструкцию.

Обычная идиома состоит в том, чтобы вызвать int child_pid = fork(), а затем проверить child_pid, чтобы определить, являюсь ли я дочерним процессом (child_pid == 0) или родительским процессом (child_pid != 0), и продолжить либо exec()ing, либо wait()ing в зависимости от ситуации.

Вы не прошли этот тест; оба ваших процесса пытаются выполнять оба поведения.

Этого должно быть достаточно, чтобы направить вас на правильный путь.

РЕДАКТИРОВАТЬ: я только что скомпилировал следующее:

/**
* @file     msh.c
* @brief    fork/execl example
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char* argv[])
{

    int pid;


    if ((pid = fork()) == 0)
    {
        if(strcmp(argv[1], "mycopy") == 0)
        {
            {
                execl("./hello", "./hello", argv[2], argv[3], NULL);
            }
        }

        if(strcmp(argv[1], "myremove") == 0)
        {
            {
                execl("./hello", "./hello", argv[2], NULL);
            }
        }

        if(strcmp(argv[1], "mymove") == 0)
        {
            {
                execl("./hello", "./hello", argv[2], argv[3], NULL);
            }
        }
    }
    else
    {
        wait(NULL);
    }

    return 0;
}

(снова отредактировано) и

/**
* @file     hello.c
* @brief    test load for msh
*/

#include <stdio.h>

int main(int argc, char* argv[])
{
    int i;
    for (i = 0; i < argc; i++)
        printf("Argc[%d] = %s\n", i, argv[i]);
    return 0;
}

и это работает, так что, возможно, проблема в вашем дочернем коде?

Я заметил, что execl() передает свой второй аргумент как дочерний argv[0], так что это может вызвать у вас проблемы.

person Darwin von Corax    schedule 19.11.2015
comment
Технически if(child_pid == 0) у нас есть дочерний процесс. if(child_pid > 0) у нас есть родительский процесс и if(child_pid < 0) у нас есть ошибка - person TheQAGuy; 19.11.2015
comment
отлично сейчас попробую - person Mkey; 19.11.2015
comment
Я обновил свой исходный пост, чтобы отразить мою реализацию того, что вы сказали, и мне все еще не повезло. - person Mkey; 19.11.2015
comment
Что происходит сейчас? Попробуйте временно заменить свои myxxx программы на простые helloWorld, просто чтобы посмотреть, работает ли у вас разветвление. - person Darwin von Corax; 19.11.2015
comment
strace -f ./msh mycopy file1 file2 может помочь понять, что на самом деле делает ваше приложение. Но кто-то думает, что в fork отсутствует только объяснение, что функции exec возвращаются только при ошибках. Если функция exec выполнена успешно, она заменяет ваш процесс тем, который вы запросили при вызове. - person Pauli Nieminen; 19.11.2015
comment
Итак, мой процесс msh теперь будет перезаписан кодом mycopy? Или что именно вы имеете в виду? Я новичок в линуксе. Я понимаю fork() до определенного момента и что он делает на самом деле, но я не уверен в execl - person Mkey; 19.11.2015
comment
Когда ваш процесс вызывает exec(), его код перезаписывается программой execed. Это то, что вы хотите, чтобы ваш дочерний процесс делал; это то, как только что порожденный msh дочерний процесс становится программой, которую вы на самом деле хотели запустить как дочерний процесс. Как я уже сказал: умопомрачительный. - person Darwin von Corax; 19.11.2015
comment
Я только что нашел это в пыльных глубинах моего меню закладок: Учебное пособие по fork() из Большого руководства Beej по межпроцессному взаимодействию в Unix. Это немного поверхностно, но включает пример кода. - person Darwin von Corax; 19.11.2015
comment
Итак, я понимаю, что fork и execl и проверка pid и все такое, но это все еще не работает :'((((((( - person Mkey; 19.11.2015
comment
Я обновил свой исходный пост, чтобы показать, где я нахожусь. Понятия не имею, почему это не работает, а strace была нераспознанной командой в моем Linux-боксе. - person Mkey; 19.11.2015
comment
Я заменил mycopy на printf, чтобы увидеть, работает ли вилка, и это так. Но когда я заменяю printf на execl, он не делает то, что должен. - person Mkey; 19.11.2015
comment
Возможно, вы захотите убедиться, что установлены хорошие инструменты отладки, прежде чем начинать писать код. Мой краткий список, который мне как минимум необходимо установить: gdb, strace, ltrace, valgrind и perf. Также мне нравится устанавливать справочные страницы из manpages-dev и manpages-posix-dev: fork, exec и подождите - person Pauli Nieminen; 19.11.2015
comment
Я нахожусь в школьном виртуальном ящике, поэтому у меня нет большого доступа для установки другого программного обеспечения. :/ - person Mkey; 19.11.2015
comment
Для mycopy это должен быть path/./mycopy или просто path/mycopy? - person Mkey; 19.11.2015
comment
Таким образом, это должно быть path/mycopy, NULL, argv[1], argv[2], чтобы mycopy argv[1] было тем, что указано в параметрах - person Mkey; 19.11.2015
comment
Три решения для использования отсутствующих инструментов в школе 1) Загрузите исходный код и скомпилируйте отсутствующие инструменты (установите префикс в вашем домашнем каталоге и используйте LD_LIBRARY_PATH для динамических библиотек) 2) загрузите двоичные пакеты для своего дистрибутива и вручную извлеките содержимое в свой домашний каталог (Это работает не для всех инструментов). 3) Попросите администраторов школы установить недостающие инструменты программирования. Другим, вероятно, они тоже понадобятся, поэтому удивительно, что они не установлены. - person Pauli Nieminen; 19.11.2015
comment
Он должен быть execl("path/to/mycopy", "path/to/mycopy", argv[1], argv[2], (char *)NULL);, чтобы mycopy получил собственное имя как argv[0]. Аргумент NULL для execl() является дозорным, что означает игнорировать все после этого. - person Darwin von Corax; 19.11.2015
comment
В вашем коде mycopy есть несколько собственных проблем, но они не относятся к текущему разговору. Я думаю, что проблема, с которой вы столкнулись сейчас, связана именно с взаимодействием между execl() и mycopy, и ссылка на Beej's Guide, которую я разместил ранее, должна помочь с этим, как и текущая версия примера кода, который я разместил. . - person Darwin von Corax; 19.11.2015