繁体   English   中英

用C管道的Shell程序

[英]Shell program with pipes in C

我有管道问题。 我的程序是C中的Shell程序。我想执行例如ls | wc ls | wc ,但我跑完后得到的是:

ls:无法访问|:没有这样的文件或目录ls:无法访问wc:没有这样的文件或目录。

我究竟做错了什么?

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

#define MAX_CMD_LENGTH 100

#define MAX_NUM_PARAMS 10

int parsecmd(char* cmd, char** params) { //split cmd into array of params
    int i,n=-1;
    for(i=0; i<MAX_NUM_PARAMS; i++) {
        params[i] = strsep(&cmd, " ");
        n++;
        if(params[i] == NULL) break;
    }
    return(n);
};

int executecmd(char** params) {
    pid_t pid = fork(); //fork process

    if (pid == -1) { //error
        char *error = strerror(errno);
        printf("error fork!!\n");
        return 1;
    } else if (pid == 0) { // child process
        execvp(params[0], params); //exec cmd
        char *error = strerror(errno);
        printf("unknown command\n");
        return 0;
    } else { // parent process
        int childstatus;
        waitpid(pid, &childstatus, 0);    
        return 1;
    }
};

int execpipe (char ** argv1, char ** argv2) {
    int fds[2];
    pipe(fds);
    int i;
    pid_t pid = fork();
    for (i=0; i<2; i++) {
        if (pid == -1) { //error
            char *error = strerror(errno);
            printf("error fork!!\n");
            return 1;
         } else
             if (pid == 0) {
                 if(i ==0){
                     close(fds[1]);
                     dup2(fds[0], 0);
                     close(fds[0]);
                     execvp(argv1[0], argv1);
                     char *error = strerror(errno);
                     printf("unknown command\n");
                     return 0;
                 } else if(i == 1) { 
                     close(fds[0]);
                     dup2(fds[1], 1);
                     close(fds[1]);
                     execvp(argv2[0], argv2);
                     char *error = strerror(errno);
                     printf("unknown command\n");
                     return 0;
                 }
            } else { // parent process
                int childstatus;
                waitpid(pid, &childstatus, 0);
                return 1;
            }
    } // end for
};


int main() {    
    char cmd[MAX_CMD_LENGTH+1];    
    char * params[MAX_NUM_PARAMS+1];    
    char * argv1[MAX_NUM_PARAMS+1];    
    char * argv2[MAX_NUM_PARAMS+1];    
    int k, y, x;    
    int f = 1;    
    while(1) {
        printf("$"); //prompt    
        if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit       
        if(cmd[strlen(cmd)-1] == '\n') { //remove newline char    
            cmd[strlen(cmd)-1] = '\0';    
        }    
        int j=parsecmd(cmd, params); //split cmd into array of params           
        if (strcmp(params[0], "exit") == 0) break; //exit   
        for (k=0; k <j; k++) { //elegxos gia uparksi pipes    
            if (strcmp(params[k], "|") == 0) {    
                f = 0; y = k;      
               printf("pipe found\n");
            }               
        }
        if (f==0) {
            for (x=0; x<k; x++) {    
               argv1[x]=params[x];
            }     
            int z = 0;     
            for (x=k+1; x< j; x++) {     
                argv2[z]=params[x];
                z++;
            }     
            if (execpipe(argv1, argv2) == 0) break;    
         } else if (f==1) {     
             if (executecmd(params) == 0) break;
         }
    } // end while
    return 0;
}

通过以下更正更新了您的代码。

  1. 删除for()循环,在fork()调用后迭代两次。
  2. dup2调用父进程和子进程后,删除了管道FD的错误关闭。
  3. 根据在父和子的dup2()调用中重复的文件描述符,对齐需要运行的命令。 基本上我需要交换execvp(argv2[0], argv2)execvp(argv1[0], argv1)调用。
  4. 增加break; 搜索管道字符的for循环中的语句。

更新后的代码如下。

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

#define MAX_CMD_LENGTH 100

#define MAX_NUM_PARAMS 10

int parsecmd(char* cmd, char** params) { //split cmd into array of params
    int i,n=-1;
    for(i=0; i<MAX_NUM_PARAMS; i++) {
        params[i] = strsep(&cmd, " ");
        n++;
        if(params[i] == NULL) break;
    }
    return(n);
};

int executecmd(char** params) {
    pid_t pid = fork(); //fork process

    if (pid == -1) { //error
        char *error = strerror(errno);
        printf("error fork!!\n");
        return 1;
    } else if (pid == 0) { // child process
        execvp(params[0], params); //exec cmd
        char *error = strerror(errno);
        printf("unknown command\n");
        return 0;
    } else { // parent process
        int childstatus;
        waitpid(pid, &childstatus, 0);    
        return 1;
    }
};

int execpipe (char ** argv1, char ** argv2) {
    int fds[2];
    pipe(fds);
    int i;
    pid_t pid = fork();
    if (pid == -1) { //error
        char *error = strerror(errno);
        printf("error fork!!\n");
        return 1;
    } 
    if (pid == 0) { // child process
        close(fds[1]);
        dup2(fds[0], 0);
        //close(fds[0]);
        execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
        char *error = strerror(errno);
        printf("unknown command\n");
        return 0;
    } else { // parent process
        close(fds[0]);
        dup2(fds[1], 1);
        //close(fds[1]);
        execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
        char *error = strerror(errno);
        printf("unknown command\n");
        return 0;
    }
};


int main() {    
    char cmd[MAX_CMD_LENGTH+1];    
    char * params[MAX_NUM_PARAMS+1];    
    char * argv1[MAX_NUM_PARAMS+1] = {0};    
    char * argv2[MAX_NUM_PARAMS+1] = {0};    
    int k, y, x;    
    int f = 1;    
    while(1) {
        printf("$"); //prompt    
        if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit       
        if(cmd[strlen(cmd)-1] == '\n') { //remove newline char    
            cmd[strlen(cmd)-1] = '\0';    
        }    
        int j=parsecmd(cmd, params); //split cmd into array of params           
        if (strcmp(params[0], "exit") == 0) break; //exit   
        for (k=0; k <j; k++) { //elegxos gia uparksi pipes    
            if (strcmp(params[k], "|") == 0) {    
                f = 0; y = k;      
               printf("pipe found\n");
               break;
            }               
        }
        if (f==0) {
            for (x=0; x<k; x++) {    
               argv1[x]=params[x];
            }     
            int z = 0;     
            for (x=k+1; x< j; x++) {     
                argv2[z]=params[x];
                z++;
            }     
            if (execpipe(argv1, argv2) == 0) break;    
         } else if (f==1) {     
             if (executecmd(params) == 0) break;
         }
    } // end while
    return 0;
}

如果您只对我所做的更改感兴趣,那么这是您的代码与上述更新代码之间的差异:

--- original.c
+++ updated.c
@@ -4,6 +4,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/types.h>
+#include <sys/wait.h>

 #define MAX_CMD_LENGTH 100

@@ -43,44 +44,36 @@
     pipe(fds);
     int i;
     pid_t pid = fork();
-    for (i=0; i<2; i++) {
         if (pid == -1) { //error
             char *error = strerror(errno);
             printf("error fork!!\n");
             return 1;
-         } else
-             if (pid == 0) {
-                 if(i ==0){
+    } 
+    if (pid == 0) { // child process
                      close(fds[1]);
                      dup2(fds[0], 0);
-                     close(fds[0]);
-                     execvp(argv1[0], argv1);
+        //close(fds[0]);
+        execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
                      char *error = strerror(errno);
                      printf("unknown command\n");
                      return 0;
-                 } else if(i == 1) { 
+    } else { // parent process
                      close(fds[0]);
                      dup2(fds[1], 1);
-                     close(fds[1]);
-                     execvp(argv2[0], argv2);
+        //close(fds[1]);
+        execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
                      char *error = strerror(errno);
                      printf("unknown command\n");
                      return 0;
                  }
-            } else { // parent process
-                int childstatus;
-                waitpid(pid, &childstatus, 0);
-                return 1;
-            }
-    } // end for
 };


 int main() {    
     char cmd[MAX_CMD_LENGTH+1];    
     char * params[MAX_NUM_PARAMS+1];    
-    char * argv1[MAX_NUM_PARAMS+1];    
-    char * argv2[MAX_NUM_PARAMS+1];    
+    char * argv1[MAX_NUM_PARAMS+1] = {0};    
+    char * argv2[MAX_NUM_PARAMS+1] = {0};    
     int k, y, x;    
     int f = 1;    
     while(1) {
@@ -95,6 +88,7 @@
             if (strcmp(params[k], "|") == 0) {    
                 f = 0; y = k;      
                printf("pipe found\n");
+               break;
             }               
         }
         if (f==0) {

execv*过程不解释shell脚本字符串。 它只是启动一个可执行文件并将一个参数数组传递给它。 因此,它无法组织管道。

如果需要“正常”shell命令执行,则可能需要使用system(char*)过程而不是execvp。

否则,如果您需要自己管道,可能需要用“|”解析字符串 特殊字符并使用pipe(),fork()和I / O重定向。 像这里如何使用管道运行命令?

暂无
暂无

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

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