C Shell:重定向和管道工作,但不是输入和输出重定向与1个或多个管道的组合

时间:2017-10-12 17:22:15

标签: c shell operating-system pipe

我的C shell可以成功处理重定向(例如ls -al> output.txt,./ pre< input1.txt等)和多个管道(即cmd1 | cmd 2 | cmd 3)。但是,当我尝试与管道一起进行输入和输出重定向时,我的代码不起作用,例如./pre< input.txt | ./sort> output.txt的。尽管./pre成功执行,但没有输出文件。

pre是一个可执行文件,可以使用超过3.0的GPA打印名称

sort是一个按字母顺序排列名称列表的可执行文件 input.txt是一个带有名称和GPA的文件(名称3.1 ...)。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#ifndef READ
#define READ 0
#endif

#ifndef WRITE
#define WRITE 1
#endif

void clearArgumentContainer (int argumentContainer[]);

int main() {
    /* professor-supplied variables for commands and command parsing */
    char *iPath, *oPath, *argv[20], buf[80], n, *p;
    int m, status, inword, continu;

    int start[20];

    /* flags for redirection (note: C does not have type bool; using integer value 0 or 1) */
    int inputRedirectFlag, outputRedirectFlag;

    /* variables for piping */
    int count, pipes;
    pid_t pid;

    /* pipes */
    int l_pipe[2], r_pipe[2];

    /* required container for handling arguments */
    int argumentContainer[20] = { 0 };

    while (1) {

        inword = m = continu = count = pipes = pid = 0;

        p = buf;

        /* redirection flags reset */
        inputRedirectFlag = outputRedirectFlag = 0;

        /* shell prompt */
        printf("\nshhh> ");

        /* command parsing */
        while ((n = getchar()) != '\n' || continu)
        {
            if (n == ' ') {
                if (inword)
                {
                    inword = 0;
                    *p++ = 0;
                }
            }
            else if (n == '\n')
                continu = 0;
            else if (n == '\\' && !inword)
                continu = 1;
            else {
                if (!inword)
                {
                    inword = 1;
                    argv[m++] = p;
                    *p++ = n;
                }
                else
                    *p++ = n;
            }
        } /* end of command parsing */

        *p++ = 0;
        argv[m] = 0;

        /* user wishes to terminate program */
        if (strcmp(argv[0], "exit") == 0)
            exit(0);

        /* manage redirection */
        while (argv[count] != 0) {
            if (strcmp(argv[count], "|") == 0) {
                argv[count] = 0;
                argumentContainer[pipes + 1] = count + 1;
                ++pipes;
            }
            else if (strcmp(argv[count], "<") == 0) {
                iPath = strdup(argv[count + 1]); /* copy string argument (file string) */
                argv[count] = 0;
                argv[count + 1] = 0;
                inputRedirectFlag = 1;
            }
            else if (strcmp(argv[count], ">") == 0) {
                oPath = strdup(argv[count + 1]); /* copy string argument (file string) */
                argv[count] = 0;
                argv[count + 1] = 0;
                outputRedirectFlag = 1;
            }
            else {
                argumentContainer[count] = count;
            }

            ++count;
        } /* end of redirection management */

        /* execute commands [<= in for-loop; n pipes require n+1 processes] */
        for (int index = 0; index <= pipes; ++index) {
            if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */
                pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */
            }

            /* switch-statement for command execution */
            switch (pid = fork()) {
                /* fork() error */
                case -1: perror("fork failed");
                         break;

                case 0: /* child process manages redirection and executes */
                       if ((index == 0) && (inputRedirectFlag == 1)) {
                           int inputFileDescriptor = open(iPath, O_RDONLY , 0400);
                           if (inputFileDescriptor == -1) {
                               perror("input file failed to open\n");
                               return(EXIT_FAILURE);
                           }
                           close(READ);
                           dup(inputFileDescriptor);
                           close(inputFileDescriptor);
                       } /* end of input redirection management */

                       if ((index == pipes) && (outputRedirectFlag == 1)) {
                           int outputFileDescriptor = open(oPath, O_WRONLY | O_CREAT, 0755);
                           if (outputFileDescriptor < 0) {
                               perror("output file failed to open\n");
                               return(EXIT_FAILURE);
                           }
                           close(WRITE);
                           dup(outputFileDescriptor);
                           close(outputFileDescriptor);
                       } /* end of output redirection management */

                        /* manage pipes if (a) first child process, (b) middle child process, or (c) third/final child process */
                        if (pipes > 0) {
                            if (index == 0){ /* first child process */
                                close(WRITE);
                                dup(r_pipe[WRITE]);
                                close(r_pipe[WRITE]);
                                close(r_pipe[READ]);
                            }
                            else if (index < pipes) { /* middle child process */
                                close(READ);
                                dup(l_pipe[READ]);
                                close(l_pipe[READ]);
                                close(l_pipe[WRITE]);
                                close(WRITE);
                                dup(r_pipe[WRITE]);
                                close(r_pipe[READ]);
                                close(r_pipe[WRITE]);
                            }
                            else { /* third/final child process */
                                close(READ);
                                dup(l_pipe[READ]);
                                close(l_pipe[READ]);
                                close(l_pipe[WRITE]);
                            }
                        }

                       /* execute command */
                       execvp(argv[argumentContainer[index]], &argv[argumentContainer[index]]);

                       /* if execvp() fails */
                       perror("execution of command failed\n");

                       break;

                default: /* parent process manages the pipes for child process(es) */
                        if (index > 0) {
                            close(l_pipe[READ]);
                            close(l_pipe[WRITE]);
                        }
                        l_pipe[READ] = r_pipe[READ];
                        l_pipe[WRITE] = r_pipe[WRITE];

                        /* parent waits for child process to complete */
                        wait(&status);

                        break;
            } /* end of switch-statement for command execution */
        } /* end of loop for all pipes */

        // clear all executed commands
        for (int i = 0; i < 20; ++i) {
            argv[i] = 0;
        }
    }
}

void clearArgumentContainer (int argumentContainer[]){
    // clear argument container
    for (int i = 0; i < 20; ++i) {
        argumentContainer[i] = 0;
    }
}

这是我正在使用的输入文件:

Tim 3.5
Todd 2.1
Beth 3.9
Jason 3.5
Zander 3.3
Alex 3.5
Tyler 3.5
Lauren 3.6
Jack 2.3
Amir 3.4
Beth 3.2

pre executable将仅列出GPA高于3.0的名称 sort executable将按字母顺序对名称列表进行排序

1 个答案:

答案 0 :(得分:1)

这是我最后的工作代码。它没有实现像cd这样的内置函数,但我计划尽快实现这些内置函数!计划确实符合任务要求。

我的主要更改发生在重定向处理中。我不得不在两个地方删除一行代码:

argv[count + 1] = 0;

从&#34;&lt;&#34;的重定向和&#34;&gt;。&#34;

我还添加了代码来处理管道的连接,无论我的进程是第一个子进程,最后一个进程还是介于两者之间。

代码:

/***********************************************************************************************
 ***********************************************************************************************
 Student: Douglas Adolph
 Course: Operating Systems
 Project #: 2

 Program emulates shell, and can do the following:

 1. Can execute a command with the accompanying arguments.
 2. Recognize multiple pipe requests and handle them.
 3. Recognize redirection requests and handle them.
 4. Type "exit" to quit the shhh shell.

 Notes:

 Shell built-ins (cd, echo, etc.) not yet implemented

 REFERENCED:

 1. http://www.thinkplexx.com/learn/article/unix/command
 2. http://man7.org/linux/man-pages/man2/open.2.html
 3. https://stackoverflow.com/questions/19846272/redirecting-i-o-implementation-of-a-shell-in-c
 **********************************************************************************************
 *********************************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#ifndef READ
#define READ 0
#endif

#ifndef WRITE
#define WRITE 1
#endif

void clearArgIndexContainer (int argLocation[]);

int main() {
    /* variables for command parsing and storage*/
    char n, *parser, buf[80], *argv[20];
    int m, status, inword, continu;

    /* variables and flags for redirection (note: C does not have type bool; using integer value 0 or 1) */
    char *in_path, *out_path;
    int inputRedirectFlag, outputRedirectFlag;

    /* variables for piping */
    int count, pipes;
    pid_t pid;

    /* left and right pipes */
    int l_pipe[2], r_pipe[2];

    /* container for recording argument locations in argv[] */
    int argLocation[20] = { 0 };

    while (1) {

        /* reset parsing and piping variable values */
        m = inword = continu = count = pipes = pid = 0;

        /* begin parsing at beginning of buffer */
        parser = buf;

        /* reset redirection flags */
        inputRedirectFlag = outputRedirectFlag = 0;

        /* print shell prompt */
        printf("\nshhh> ");

        /* parse commands */
        while ((n = getchar()) != '\n' || continu)
        {
            if (n == ' ') {
                if (inword)
                {
                    inword = 0;
                    *parser++ = 0;
                }
            }
            else if (n == '\n')
                continu = 0;
            else if (n == '\\' && !inword)
                continu = 1;
            else {
                if (!inword)
                {
                    inword = 1;
                    argv[m++] = parser;
                    *parser++ = n;
                }
                else
                    *parser++ = n;
            }
        } /* end of command parsing */

        /* append terminating character to end of parser buffer and argv buffer */
        *parser++ = 0;
        argv[m] = 0;

        /* user wishes to terminate program */
        if (strcmp(argv[0], "exit") == 0)
            exit(0);

        /* manage redirection */
        while (argv[count] != 0) {
            if (strcmp(argv[count], "|") == 0) {
                argv[count] = 0;
                argLocation[pipes + 1] = count + 1;
                ++pipes;
            }
            else if (strcmp(argv[count], "<") == 0) {
                in_path = strdup(argv[count + 1]);
                argv[count] = 0;
                inputRedirectFlag = 1;
            }
            else if (strcmp(argv[count], ">") == 0) {
                out_path = strdup(argv[count + 1]);
                argv[count] = 0;
                outputRedirectFlag = 1;
            }
            else {
                argLocation[count] = count;
            }

            ++count;
        } /* end of redirection management */

        /* execute commands [<= in for-loop; n pipes require n+1 processes] */
        for (int index = 0; index <= pipes; ++index) {
            if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */
                pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */
            }

            /* switch-statement for command execution */
            switch (pid = fork()) {
                case -1: perror("fork failed"); /* fork() error */
                         break;

                case 0: /* child process manages redirection and executes */
                       if ((index == 0) && (inputRedirectFlag == 1)) {
                           int inputFileDescriptor = open(in_path, O_RDONLY , 0400);
                           if (inputFileDescriptor == -1) {
                               perror("input file failed to open\n");
                               return(EXIT_FAILURE);
                           }
                           close(READ);
                           dup(inputFileDescriptor);
                           close(inputFileDescriptor);
                       } /* end of input redirection management */

                       if ((index == pipes) && (outputRedirectFlag == 1)) {
                           //printf("DEBUG: here we should be about to create our output file\n");
                           int outputFileDescriptor = creat(out_path, 0700);
                           if (outputFileDescriptor < 0) {
                               perror("output file failed to open\n");
                               return(EXIT_FAILURE);
                           }
                           close(WRITE);
                           dup(outputFileDescriptor);
                           close(outputFileDescriptor);
                       } /* end of output redirection management */

                        /* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */
                        if (pipes > 0) {
                            if (index == 0){ /* first child process */
                                close(WRITE);
                                dup(r_pipe[WRITE]);
                                close(r_pipe[WRITE]);
                                close(r_pipe[READ]);
                            }
                            else if (index < pipes) { /* in-between child process */
                                close(READ);
                                dup(l_pipe[READ]);
                                close(l_pipe[READ]);
                                close(l_pipe[WRITE]);
                                close(WRITE);
                                dup(r_pipe[WRITE]);
                                close(r_pipe[READ]);
                                close(r_pipe[WRITE]);
                            }
                            else { /* final child process */
                                close(READ);
                                dup(l_pipe[READ]);
                                close(l_pipe[READ]);
                                close(l_pipe[WRITE]);
                            }
                        }

                       /* execute command */
                       execvp(argv[argLocation[index]], &argv[argLocation[index]]);

                       /* if execvp() fails */
                       perror("execution of command failed\n");

                       break;

                default: /* parent process manages the pipes for child process(es) */
                        if (index > 0) {
                            close(l_pipe[READ]);
                            close(l_pipe[WRITE]);
                        }
                        l_pipe[READ] = r_pipe[READ];
                        l_pipe[WRITE] = r_pipe[WRITE];

                        /* parent waits for child process to complete */
                        wait(&status);

                        break;
            } /* end of switch-statement for command execution */
        } /* end of loop for all pipes */

        // clear all executed commands
        for (int i = 0; i < 20; ++i) {
            argv[i] = 0;
        }
    }
}

void clearArgIndexContainer (int argLocation[]){
    // clear argument container
    for (int i = 0; i < 20; ++i) {
        argLocation[i] = 0;
    }
}

这是我删除了argv [count + 1] = 0的行; :

/* manage redirection */
    while (argv[count] != 0) {
        if (strcmp(argv[count], "|") == 0) {
            argv[count] = 0;
            argLocation[pipes + 1] = count + 1;
            ++pipes;
        }
        else if (strcmp(argv[count], "<") == 0) {
            in_path = strdup(argv[count + 1]);
            argv[count] = 0;
            inputRedirectFlag = 1;
        }
        else if (strcmp(argv[count], ">") == 0) {
            out_path = strdup(argv[count + 1]);
            argv[count] = 0;
            outputRedirectFlag = 1;
        }
        else {
            argLocation[count] = count;
        }

这是我处理管道的主要补充:

/* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */
                        if (pipes > 0) {
                            if (index == 0){ /* first child process */
                                close(WRITE);
                                dup(r_pipe[WRITE]);
                                close(r_pipe[WRITE]);
                                close(r_pipe[READ]);
                            }
                            else if (index < pipes) { /* in-between child process */
                                close(READ);
                                dup(l_pipe[READ]);
                                close(l_pipe[READ]);
                                close(l_pipe[WRITE]);
                                close(WRITE);
                                dup(r_pipe[WRITE]);
                                close(r_pipe[READ]);
                                close(r_pipe[WRITE]);
                            }
                            else { /* final child process */
                                close(READ);
                                dup(l_pipe[READ]);
                                close(l_pipe[READ]);
                                close(l_pipe[WRITE]);
                            }
                        }

我还有很多工作要做,即实现内置函数,还要将更多内容放入单独的函数中来清理代码并使其更具可读性。我也对一些可能写得更好的表达给了一些很好的建议,我很快就会解决这个问题。