简体   繁体   中英

stdin into execvp() while using fork() and pipe()

So I am trying to read from standard input and then get the input ready so that later on it can be used inside execvp().

What I am implementing here is basically a pipe for some terminal commands.

Here is how an example of my code goes.

input:

ls -s1

sort -n

output:

commands[0]="ls"

commands[1]="-s1"

commands2[0]="��""

commands2[1]="��""

sort: cannot read: t: No such file or directory

Here is my code

# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>
# include <string.h>
# include <sys/wait.h>
# define BUF_SIZE 256
    

int main()
{
    char buffer[BUF_SIZE];
    char *commands[5];
    char *commands2[5];
    int argc = 0;
    int argc2 = 0;

    fgets(buffer, BUF_SIZE, stdin);
        
        for ( commands[argc] = strtok(buffer, " \t\n"); 
              commands[argc] != NULL; 
              commands[++argc] = strtok(NULL, " \t\n") ) {
            printf("commands[%d]=\"%s\"\n", argc, commands[argc]);
        }
        commands[argc] = NULL;

    fgets(buffer, BUF_SIZE, stdin);
        
        for ( commands2[argc2] = strtok(buffer, " \t\n"); 
              commands2[argc2] != NULL; 
              commands2[++argc2] = strtok(NULL, " \t\n") ) {
            printf("commands2[%d]=\"%s\"\n", argc2, commands2[argc]);
        }
        commands2[argc2] = NULL;

    int my_pipe[2];

    if (pipe(my_pipe) == -1)
    {
        perror("cannot create pipe\n");
    }

    pid_t my_pid;

    my_pid = fork();

    if (my_pid < 0)
    {
        perror("Failed fork\n");
    }

    if (my_pid > 0)
    {
        close(my_pipe[1]);
        dup2(my_pipe[0], 0);
        close(my_pipe[0]);

        wait(NULL);
        execvp(commands2[0],commands2); 
    }
    else
    {
        close(my_pipe[0]);   
        dup2(my_pipe[1], 1);
        close(my_pipe[1]);

        execvp(commands[0],commands);
    }
}

One major problem is that you read the second line over the first in buffer , and the commands[] array contains pointers into buffer too. That's not a recipe for happiness. The simplest fix is to define char buffer2[BUF_SIZE]; and use that in the second fgets() call and for loop.

Using argc in printf("commands2[%d]=\"%s\"\n", argc2, commands2[argc]); is a copy'n'paste bug — it should reference argc2 twice. This helped hide the previous problem.

Note that perror() does not exit; your code blunders on if pipe() fails, or if fork() fails.

The wait() in if (my_pid > 0) is bad; remove it.

If execvp() fails, you should report an error and exit with a non-zero status.

Putting those changes together yields code such as:

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

#define BUF_SIZE 256

int main(void)
{
    char buffer[BUF_SIZE];
    char buffer2[BUF_SIZE];
    char *commands[5];
    char *commands2[5];
    int argc = 0;
    int argc2 = 0;

    fgets(buffer, BUF_SIZE, stdin);

    for (commands[argc] = strtok(buffer, " \t\n");
         commands[argc] != NULL;
         commands[++argc] = strtok(NULL, " \t\n"))
    {
        printf("commands[%d]=\"%s\"\n", argc, commands[argc]);
    }
    commands[argc] = NULL;

    fgets(buffer2, BUF_SIZE, stdin);

    for (commands2[argc2] = strtok(buffer2, " \t\n");
         commands2[argc2] != NULL;
         commands2[++argc2] = strtok(NULL, " \t\n"))
    {
        printf("commands2[%d]=\"%s\"\n", argc2, commands2[argc2]);
    }
    commands2[argc2] = NULL;

    int my_pipe[2];

    if (pipe(my_pipe) == -1)
    {
        perror("cannot create pipe\n");
        exit(EXIT_FAILURE);
    }

    pid_t my_pid = fork();

    if (my_pid < 0)
    {
        perror("Failed fork\n");
        exit(EXIT_FAILURE);
    }

    if (my_pid > 0)
    {
        close(my_pipe[1]);
        dup2(my_pipe[0], 0);
        close(my_pipe[0]);

        execvp(commands2[0], commands2);
        perror(commands2[0]);
        exit(EXIT_FAILURE);
    }
    else
    {
        close(my_pipe[0]);
        dup2(my_pipe[1], 1);
        close(my_pipe[1]);

        execvp(commands[0], commands);
        perror(commands[0]);
        exit(EXIT_FAILURE);
    }
    return EXIT_FAILURE;
}

When I run the program, it produces the appropriate output. Note that the return at the end of main() is actually never reached.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM