简体   繁体   English

C管道-命令2错误

[英]Piping in C - Error in Command 2

So, I thought I was on the right track with trying to imitate the bash shell, but I'm having issues piping. 因此,我认为我在模仿bash外壳方面走上了正确的轨道,但是我在管道方面遇到了问题。 I am getting an error executing the second command. 执行第二个命令时出现错误。 I was wondering if someone could explain to me how to fix this and why it's going wrong. 我想知道是否有人可以向我解释如何解决此问题以及为什么会出错。 I'm very new to C & Linux commands so any supplemental information that could help me along the way would be also be appreciated. 我对C和Linux命令非常陌生,因此也将对任何可以帮助我的补充信息表示赞赏。

Thank you so much for your time. 非常感谢您的参与。 My code is below, but there is a lot of it. 我的代码在下面,但是有很多。 My issue is occurring in the exec_pipe function. 我的问题发生在exec_pipe函数中。 I would normally include what I have used for input and what I am getting for output, but my sample input is actually executable files my professor gave us for testing. 我通常会包括我用于输入的内容以及我将用于输出的内容,但是我的示例输入实际上是教授提供给我们进行测试的可执行文件。 Unfortunately, mine is not working like it does in the shell. 不幸的是,我的外壳无法像在外壳中那样工作。 I am just getting my error print out: 我只是打印出我的错误:

Inside Case 5
Inside Exec_Pipe
Error in Pipe EXECVP cmd2

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>
#include <time.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/wait.h>
#define BUFSIZE 1024
#define CSTRSIZE 100
#define CMDSIZE 30
#define DEBUG 1

//I referenced our blackboard source code files to create the fork functions and to deal with file descriptors
void exec_cmd(char** cmd1){
    pid_t pid;
    if((pid = fork()) < 0){
        printf("Child Process Failed\n");
    }else if(pid == 0){
        if(execvp(cmd1[0], cmd1) < 0){
            printf("Execution Failed\n"); 
            exit(1);
        }
    }else{
       wait(NULL);
    }
}
void exec_cmd_in(char** cmd1, char* infile){
    pid_t pid;
    int fdi;
    if((pid = fork()) < 0){
          printf("Child Process Failed\n");
    }else if(pid == 0){
        fdi = open(infile, O_RDONLY);
        if(fdi == -1){
            printf("No Infile");
        }
    }
}
void exec_cmd_opt_in_append(char** cmd1, char* infile, char* outfile){
   /* pid_t pid;
    int fdi, fdo;
    if((pid = fork()) < 0){
          printf("Child Process Failed\n");
    }else if(pid == 0){
        fdo = open(outfile, O_RDWR | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
        if(fdo == -1){
            printf("No Outfile");
        }
        if(dup2(fdi, 0) == -1){
            printf("Infile not updated");
        }
        if(dup2(fdo, 1) == -1){
            printf("Outfile not updated");
        }
        close(fdi);
        close(fdo);
        if(execvp(cmd1[0], cmd1) < 0){
            printf("Execution Failed\n"); 
            exit(1);
        }
    }else{
        wait(NULL);
    } */ 
}
void exec_cmd_opt_in_write(char** cmd1, char* infile, char* outfile){
    /* pid_t pid;
    int fdi, fdo;
    if((pid = fork()) < 0 ){
        printf("Fork Error");
        exit(1);
    }else if(pid == 0 ){
        fdo = open(outfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
        if(fdo == -1){
                printf("No Outfile");
        }

        if(dup2(fdi, 0) == -1){
            printf("Infile not updated");
        }
        if(dup2(fdo, 1) == -1){
            printf("Outfile not updated");
        }
        close(fdi);
        close(fdo);
        if(execvp(cmd1[0], cmd1) < 0){
            printf("Execution Failed\n"); 
            exit(1);
        }
    }else{
        wait(NULL);
    }
  */   
}
void exec_pipe(char** cmd1, char** cmd2){
    pid_t pid;
    int pipefd[2];
    // pipe[1] is the write end of the pipe
    // pipe[0] is the read end of the pipe
    // making a pipe
    printf("Inside Exec_Pipe\n");
    pid = fork();
    switch(pid){
        case -1:
            //error in fork
            printf("Fork Error\n"); 
            //Exit
            exit(1);
        case 0:
            //child
            break;
        default:
            //parent
            wait(NULL);
    }   
    //This will be executed by child process
    if(pipe(pipefd) < 0 ) {
        //error condition
        printf("Pipe Error");
        exit(1);
    }
    pid = fork();
    switch(pid){
        case -1:
            //error in fork
            printf("Fork Error\n"); 
            //Exit
        case 0:
            //child
            close(STDIN_FILENO);
            //direct STDOUT to the pipe
            dup2(pipefd[1], STDOUT_FILENO);
            //Close descriptors
            close(pipefd[0]);
            close(pipefd[1]);
            //Execute Command1
            execvp(cmd1[0], cmd1);
            //execvp should not return, so if it does
            //there is an error!
            printf("Error in EXECVP cmd1");
            exit(1);
        default:
            //parent
            close(STDIN_FILENO);
            //direct input to the pipe
            dup2(pipefd[0],STDIN_FILENO);
            //close descriptors
            close(pipefd[0]);
            close(pipefd[1]);
            //execute command 2
            execvp(cmd2[0],cmd2);
            //if execvp makes it back, error condition
            printf("Error in Pipe EXECVP cmd2");
            exit(1);
    }   
}
void exec_pipe_opt_in_append(char** cmd1, char** cmd2, char* infile, char* outfile){

}
void exec_pipe_opt_in_write(char** cmd1, char** cmd2, char* infile, char* outfile){

}
int parse_command(char* line, char** cmd1, char** cmd2, char* infile, char* outfile){
/* 
    (1)Create a bunch of flags to compare for the right return value
    (2)Loop over the entire line and set the flags
    (3)Add a bunch of if statements to compare flags
    (4)If there is more than one flag for pipe, we can't handle it. Regurn 9.
    (5)If there is &, we can't handle.
    (6)Return the right value
*/
    int pipe_found = 0;
    int input_found = 0;
    int redirection = 0;
    int i = 0;
    int spaces = 0;
    int append = 0;
    int special = 0;
    while(line[i] != '\0'){
        if(line[i] == '|'){
            pipe_found++;
        }
        if(line[i] == '<'){
            input_found = 1;
        }
        if((line[i] == '&') || (line[i] == '*') || (line[i] == '^') || (line[i] == '%') || (line[i] == '#') || (line[i] == '!') || (line[i] == '@') || (line[i] == '(') || (line[i] == ')')){ 
            special = 1;
        }
        if(line[i] == '>'){
            redirection = 1;
            if(line[i+1] == '>'){
                append = 1;
            }
        }
        if(line[i] == ' '){
             spaces++;
        }
       i++;
    }
    if((strlen(line) >=4) && (line[0] == 'q') && (line[1] == 'u') && (line[2] == 'i') && (line[3] == 't')){
        return 0;
    }
    if((pipe_found == 0) && (special == 0)){
        if((redirection == 0) && (input_found == 0)){
            return 1;
        }else if((redirection == 0) && (input_found == 1)){
            return 2;
        }else if(append == 1){
            return 3;
        }else if(redirection == 1){
            return 4;
        }
    }else if((pipe_found == 1) && (special == 0)){
        if((redirection == 0) && (input_found == 0)){
            return 5;
        }else if((redirection == 0) && (input_found == 1)){
            return 6;
        }else if(append == 1){
            return 7;
        }else if(redirection == 1){
            return 8;
        }

    }
            return 9;
}
//I referenced StackOverflow and some online libraries to get this tokenize function
char ** tokenize(char *str, char *delim, unsigned int *number_tokens) {
    char *pch = strtok(str, delim);
    unsigned int ntok = 0;
    if(pch != NULL) {
        ntok = 1;
    }else{
        return NULL;
    }
    char **tokens = realloc(NULL, sizeof(char *)*ntok);
    tokens[ntok-1] = pch;
    while(pch != NULL) {
        pch = strtok(NULL, delim);
        ntok++;
        tokens = realloc(tokens, sizeof(char *)*ntok);
        tokens[ntok-1] = pch;
    }
    if(number_tokens) {
        *number_tokens = ntok;
    }
    return tokens;
}
//I referenced StackOverflow.com for this trim function 
char *trim(char *str) {
  char *end;
  if(str == NULL){
    return NULL;
  }
  while(isspace(*str)){
       str++;
  }
  end = str + strlen(str) - 1;
  while(end > str && isspace(*end)) {
      end--;
  }
  *(end+1) = 0;
  return str;
}

int main(int argc, char *argv[]){
    int returnValue = 0;
    char *infile = NULL;
    char *outfile = NULL;
    char **cmd = NULL;
    char **cmd1_tokens = NULL;
    char **cmd2_tokens = NULL;
    char *input;
    int current_cmd = 0;
    /*
    (1)If the user does not enter a command line argument, get one after typing "myshell-%"
    (2)Call parse_command on the user input to get the right return value
    (3)Begin parsing the user input within main
    */ 
    if(argc == 1){
        printf("myshell-%%\n"); 
        fgets (input, 20, stdin);
        returnValue = parse_command(input, cmd1_tokens, cmd2_tokens, infile, outfile);
        cmd = tokenize(input, "|", NULL);
    }else{
        returnValue = parse_command(argv[1], cmd1_tokens, cmd2_tokens, infile, outfile);
        cmd = tokenize(argv[1], "|", NULL);
    }
    int infileIt = 0;
    while(cmd[current_cmd] != NULL) {
        unsigned int number_tokens = 0;
        char **infile_token = tokenize(cmd[current_cmd], "<", &number_tokens);
        if(number_tokens > 1){
            while(infile_token[infileIt] != NULL){
                infileIt++;
            }
        }
        if(infile_token[1] != NULL) {
            number_tokens = 0;
            char **infile_outfile_token = tokenize(infile_token[1], ">", &number_tokens);
            if(number_tokens > 1){
                infile = infile_outfile_token[0];

                  infile = infile_token[1];
            }
        }
        number_tokens = 0;
        char **outfile_token = tokenize(cmd[current_cmd], ">", &number_tokens);
        if(number_tokens > 1){

                    outfile = outfile_token[1];
        }
        current_cmd++;
    }
    //Trim the in/outfiles
    infile = trim(infile);
    outfile = trim(outfile);
    /*
    Start breaking up cmd[0] and cmd[1] into smaller chunks and saving into the appropriate cmd
    */
    cmd1_tokens = tokenize(cmd[0], " ", NULL);
    if(cmd[1] != NULL){
        cmd2_tokens = tokenize(cmd[1], " ", NULL);
    }
    int cmd1Args = 0;
    while(cmd1_tokens[cmd1Args] != NULL){
        cmd1Args++;
    }
    int cmd2Args= 0;
    if(cmd2_tokens != NULL){
        while(cmd2_tokens[cmd2Args] != NULL){
            cmd2Args++;
        }
    }
    int iterator = 0;
    while((iterator < cmd1Args) && (cmd1Args != 0)){
        printf("Cmd1: %s\n", cmd1_tokens[iterator]);
        iterator++;
    }
    iterator = 0;
        while((iterator < cmd2Args)&&(cmd2Args != 0)){
        printf("Cmd2: %s\n", cmd2_tokens[iterator]);
        iterator++;
    }
    if(infile != NULL){
        printf("Infile: %s\n", infile);
    }
    if(outfile != NULL){
        printf("Outfile: %s\n", outfile);
    }

    /*Use a switch statement to process all the return values (0 ot 9) of parse_command.
    Our program should execute the “line” if the return code from parse_command
    function is 0 to 8, that is the line is deemed “valid”. For return code 9,
    our program simply output ”Not handled at this time!”.*/
    switch(returnValue){
    case 0 :
        printf("Exiting Program.\n");
        exit(1);
        break;
    case 1 :
        printf("Inside Case 1\n");
        exec_cmd(cmd1_tokens);
        break; 
    case 2 :
        printf("Inside Case 2\n");
        exec_cmd_in(cmd1_tokens, infile);
       break;
    case 3 :
        printf("Inside Case 3\n");
        exec_cmd_opt_in_append(cmd1_tokens, infile, outfile);
        break;
    case 4 :
        printf("Inside Case 4\n");
        exec_cmd_opt_in_write(cmd1_tokens, infile, outfile);
        break;
    case 5 :
        printf("Inside Case 5\n");
        exec_pipe(cmd1_tokens, cmd2_tokens);
        break;
    case 6 :
        printf("Inside Case 6\n");
        //exec_pipe_in(cmd1_tokens, cmd2_tokens, infile);
        break;
    case 7 : 
        printf("Inside Case 7\n");
        exec_pipe_opt_in_append(cmd1_tokens, cmd2_tokens, infile, outfile);
        break;
    case 8 :
        printf("Inside Case 8\n");
        exec_pipe_opt_in_write(cmd1_tokens, cmd2_tokens, infile, outfile);
        break;
    default : 
        printf("Inside Case 9\n");
        printf("Not handled at this time!\n");
}

    return 0;
}

Without having access to the input file that you're giving it, it's a little hard to say what's going on, but here are some tips for debugging it. 没有访问您提供的输入文件的权限,很难说是怎么回事,但是这里有一些调试它的技巧。

First, when something you don't understand is happening, it can be a good idea to strip it down to a minimal, working, self contained example that demonstrates the problem. 首先,当发生您不了解的事情时,最好将其简化为一个最小的,可工作的,自包含的示例 ,以证明问题所在。 Sometimes, just the process of cutting it down to that small example can help you to find the problem; 有时,仅将其缩减为一个小例子的过程就可以帮助您发现问题。 but if not, it gives you a much smaller example to ask about. 但是,如果不是这样,它会为您提供一个小得多的示例。

Next, when putting in these print statements to debug what's going on, give yourself a little more context. 接下来,在放入这些打印语句以调试正在发生的事情时,请给自己更多的上下文。 Especially in the one that indicates an error; 特别是在表示错误的那一个中; print out what the error is, and what the arguments were to the function that failed. 打印出错误是什么,以及失败函数的参数是什么。 Rather than just: 不仅仅是:

printf("Error in Pipe EXECVP cmd2");

You can use strerror to get a string representing the error number: 您可以使用strerror获得代表错误号的字符串:

printf("Error %d in Pipe EXECVP cmd2: %s\n", errno, strerror(errno));

And you can also print out what the command and all of your arguments were: 您还可以打印出命令和所有参数:

for (char **arg = cmd2; *arg != NULL; ++arg) {
    printf("cmd2[%ld] = %s", arg - cmd2, *arg);
}

Between printing out the actual error and printing out the command name and all of the arguments, that should help you to debug the problem. 在打印出实际错误与打印出命令名称和所有参数之间,这将有助于您调试问题。

If you could add that information to your question, and maybe cut your example down to a more minimal example as well as showing a minimal example of the input that causes a problem, we could probably help out a lot more. 如果您可以将这些信息添加到您的问题中,并且可以将您的示例缩减为一个更简单的示例,并显示一个导致问题的输入的最小示例,那么我们可能会提供更多帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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