Чтение/запись stdin/out для интерпретатора bash linux, fork - execl

Я пытался написать программу, которая будет отправлять и получать команды в оболочку bash (/bin/sh). Как программа-обертка вокруг оболочки bash. Итак, я могу написать на стандартный ввод «cd ~/Desktop», затем снова написать «ls», и я получу список файлов на рабочем столе. Я не могу заставить его работать. При второй команде записи в этом коде будет возвращено все, что я написал на стандартный ввод. Я также пытался использовать popen(), но это обеспечивает только вывод, не позволяя мне писать на стандартный ввод. Может ли кто-нибудь помочь решить эту проблему? Спасибо

void main()
{
    // Create a pipe and fork
    //
    int fd[2];
    int p = pipe(fd);
    pid_t pid = fork();

    if (pid > 0)
    {
        // Read from the pipe and output the result
        //
        //close(fd[1]);
        char buf[1024] = { 0 };

        read(fd[0], buf, sizeof(buf));

        printf("1 - %s\n", buf);

        write (fd[1], "ifconfig", strlen ("ifconfig") );

        // problem is here, read is returning echo'd bytes from write()

        read(fd[0], buf, sizeof(buf));

        printf("2 - %s\n", buf);    


        // Wait for child to terminate
        int status;
        wait(&status);
    }
    else if (pid == 0)
    {
        // Redirect stdout and stderr to the pipe and execute the shell
        // command
        //
        dup2(fd[0], STDIN_FILENO);
        dup2(fd[1], STDOUT_FILENO);
        dup2(fd[1], STDERR_FILENO);
        //close(fd[0]);
        execl("/bin/sh", "exec sh", "-c", "ls", (char*) NULL );
    }

}

РЕДАКТИРОВАТЬ - Обновлен код для 1-го ответа, теперь нет вывода из 2-го вызова read()

void main()
{
    // Create a pipe and fork
    //
    int fd[2];

int ChildToParent[2], ParentToChild[2];



    pipe (ParentToChild);
pipe (ChildToParent);

    pid_t pid = fork();

    if (pid > 0)
    {
        // In parent process

        // Read the output of the child from child_to_parent[0]
        // We don't need child_to_parent[1] so close it
        close(ChildToParent[1]);

        // Write output to the child using parent_to_child[1]
        // We don't need parent_to_child[0] so close it
        close(ParentToChild[0]);

        // Read from and write to the child process...
        char buf[1024] = { 0 };

        read(ChildToParent[0], buf, sizeof(buf));   
    printf("1 - %s\n", buf);


    write(ParentToChild[1], "whoami", strlen ("whoami") );

    memset (buf, 0, 1024);

    // this call to read returns nothing
    read(ChildToParent[0], buf, sizeof(buf));
    printf("2 - %s\n", buf);



    }
    else if (pid == 0)
    {
        // Redirect stdout and stderr to the pipe and execute the shell
        // command
        //
    // child_to_parent[1] is were we write output, it's the
        // new standard output, child_to_parent[0] can be closed
        dup2 (ChildToParent[1], STDOUT_FILENO);
        close(ChildToParent[0]);

        // parent_to_child[0] is where we read input from, it's the
        // new standard input, parent_to_child[1] can be closed
        dup2 (ParentToChild[0], STDIN_FILENO);
        close(ParentToChild[1]);

        //close(fd[0]);
        execl("/bin/sh", "exec sh", "-c", "ls", (char*) NULL );
    }

}


person shelly3783    schedule 08.09.2016    source источник
comment
Вам нужно два канала: один для родительского процесса для записи и дочернего процесса для чтения, а другой канал для противоположного направления.   -  person Some programmer dude    schedule 08.09.2016
comment
Разве это не то, что dup2(fd[0], STDIN_FILENO); dup2(fd[1], STDOUT_FILENO); для? Можете ли вы объяснить, о чем вы говорите, в коде.   -  person shelly3783    schedule 08.09.2016


Ответы (1)


Помните, что каналы — это односторонний коммуникационный поток. Вы не можете использовать его для двусторонней связи между двумя процессами. Для этого вам понадобятся две трубы, по одной в каждом направлении.

Возможно, что-то вроде этого простого примера:

// Pipe for the child process to write to the parent process
int child_to_parent[2];

// Pipe for the parent process to write to the child process
int parent_to_child[2];

// Create the TWO pipes
pipe(child_to_parent);
pipe(parent_to_child);

pid_t pid = fork();
if (pid > 0)
{
    // In parent process

    // Read the output of the child from child_to_parent[0]
    // We don't need child_to_parent[1] so close it
    close(child_to_parent[1]);

    // Write output to the child using parent_to_child[1]
    // We don't need parent_to_child[0] so close it
    close(parent_to_child[0]);

    // Read from and write to the child process...
}
else if (pid == 0)
{
    // In child process

    // child_to_parent[1] is were we write output, it's the
    // new standard output, child_to_parent[0] can be closed
    dup2(child_to_parent[1], STDOUT_FILENO);
    close(child_to_parent[0]);

    // parent_to_child[0] is where we read input from, it's the
    // new standard input, parent_to_child[1] can be closed
    dup2(parent_to_child[0], STDIN_FILENO);
    close(parent_to_child[1]);

    // Do whatever the child is supposed to do
}
person Some programmer dude    schedule 08.09.2016
comment
Хм, я собираюсь попробовать это, но все, что вы сделали, это добавили вызовы close() из моего исходного кода. Извините, но это все еще немного неясно, тем более, что это не скомпилируется, но я попробую... - person shelly3783; 08.09.2016
comment
Не могли бы вы указать, откуда именно я должен читать () и писать ()? - person shelly3783; 08.09.2016
comment
@ shelly3783 Подсчитайте количество каналов в моем примере по сравнению с вашим кодом ... И вы читали комментарии? Заметили две разные переменные для труб? - person Some programmer dude; 08.09.2016
comment
да, с этим редактированием я теперь вижу разницу, спасибо, я пробую. - person shelly3783; 08.09.2016
comment
Все еще не работает, я собираюсь обновить исходный код - person shelly3783; 08.09.2016
comment
Аргументы передаются на стандартный ввод в /bin/sh через командную строку, этот метод не работает для записи в стандартный ввод дочернего процесса sh. Возможно, в других ситуациях это возможно, но для /bin/sh это не так. - person shelly3783; 08.09.2016
comment
Я решил проблему, каналы нужно открывать и закрывать немного иначе, чем вы упомянули, и нужно использовать execv(), а не exec(). Код в этой ссылке работает для /bin/sh - jineshkj.wordpress.com/2006/12/22/ - вы можете отредактировать свою информацию, чтобы не создавать путаницы - person shelly3783; 08.09.2016