【问题标题】:C Shell: Redirection and piping working, but not a combination of input and output redirection with 1 or more pipesC Shell:重定向和管道工作,但不是输入和输出重定向与 1 个或多个管道的组合
【发布时间】:2018-03-24 17:43:27
【问题描述】:

我的 C shell 可以成功处理重定向(例如 ls -al > output.txt、./pre output.txt。尽管 ./pre 确实成功执行,但没有生成任何输出文件。

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

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 可执行文件将仅列出 GPA 高于 3.0 的名称 sort 可执行文件将按字母顺序对名称列表进行排序

【问题讨论】:

标签: c shell operating-system pipe


【解决方案1】:

这是我的最终工作代码。它没有实现像 cd 这样的内置插件,但我计划很快实现这些内置插件!程序确实满足作业的要求。

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

argv[count + 1] = 0;

来自“”的重定向。

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

代码:

/***********************************************************************************************
 ***********************************************************************************************
 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]);
                            }
                        }

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

【讨论】:

  • 干得好。建议您初始化char *in_path = NULL, *out_path = NULL;int l_pipe[2] = {0}, r_pipe[2] = {0}; 以消除初始化警告。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-03
  • 2016-10-21
  • 2021-10-16
  • 2023-03-04
  • 1970-01-01
  • 2012-03-22
  • 2012-03-06
相关资源
最近更新 更多