Linux   发布时间:2022-04-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了制作Linux shell时流重定向和管道大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

我有一个在C中创建 Linux sHell的任务.目前,我仍然坚持实现重定向和管道.我到目前为止的代码如下. main()解析用户的输入.如果内置命令,则执行该命令.否则,标记化的输入传递给execute()(我知道我应该把内置命令拉到自己的函数中). execute()的作用是遍历数组.如果遇到<,>或|它应该采取适当的行动.我试图正常工作的第一件事是管道.不过,我肯定做错了,因为即使是一个烟斗
@H_696_15@我有一个在C中创建 Linux sHell的任务.目前,我仍然坚持实现重定向和管道.我到目前为止的代码如下. main()解析用户的输入.如果内置命令,则执行该命令.否则,标记化的输入传递给execute()(我知道我应该把内置命令拉到自己的函数中).

execute()的作用是遍历数组.如果遇到<,>或|它应该采取适当的行动.我试图正常工作的第一件事是管道.不过,我肯定做错了,因为即使是一个烟斗也无法让它工作.例如,一个示例输入/输出

/home/ad/Documents> ls -l | grep sh
|: sh: No such file or directory
|

我的想法是让每个方向和管道仅适用于一个案例,然后通过使函数递归,我希望在同一命令行中使用多个重定向/管道.例如,我可以做program1< input1.txt> output1.txt或ls -l | grep sh> output2.txt.

我希望有人可以在尝试管道时指出我的错误,并且可能提供一些关于如何处理用户输入多个重定向/管道的情况的指示.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <String.h>
#include <stdlib.h>

int MAX_PATH_LENGTH = 1024; //Maximum path length to display.
int BUF_LENGTH = 1024; // Length of buffer to store user input
char * delims = " \n"; // Delimiters for tokenizing user input.
const int PIPE_READ = 0;
const int PIPE_WRITE = 1;

void execute(char **argArray){

  char **pA = argArray;
  int i = 0;
  while(*pA != NULL) {
    if(strcmp(argArraY[i],"<") == 0) { 
        printf("<\n"); 
    }
    else if(strcmp(argArraY[i],">") == 0) { 
        printf(">\n"); 
    }
    else if(strcmp(argArraY[i],"|") == 0) {
        int fds[2];
        pipe(fds);
        pid_t pid;
        if((pid = @L_607_18@) == 0) {
            dup2(fds[PIPE_WRITE],1);
            close(fds[PIPE_READ]);
            close(fds[PIPE_WRITE]);
            char** argList;
            memcpy(argList,argArray,i);
            execvp(argArray[0],argArray);            
        }
        if((pid = @L_607_18@) == 0) {
            dup2(fds[PIPE_READ],0);
            close(fds[PIPE_READ]);
            close(fds[PIPE_WRITE]);
            execvp(argArraY[i+1],pA);            
        }
        close(fds[PIPE_READ]);
        close(fds[PIPE_WRITE]);
        wait(null);
        wait(null);
        printf("|\n");
    }
    else { 
        if(pid == 0){
            execvp(argArray[0],argArray);
            printf("Command not found.\n");
        }
        else
            wait(null);*/
    }
    *pA++;
    i++;
  }
}

int main () {

  char path[MAX_PATH_LENGTH];
  char buf[BUF_LENGTH];
  char* strArraY[BUF_LENGTH];
  /**
   * "Welcome" message. When mash is executed,the current working directory
   * is displayed followed by >. For example,if user is in /usr/lib/,then
   * mash will display :
   *      /usr/lib/> 
   **/
  getcwd(path,MAX_PATH_LENGTH);
  printf("%s> ",path);
  fflush(stdout);

  /**
   * Loop infinitely while waiTing for input from user.
   * Parse input and display "welcome" message again.
   **/ 
  while(1) {
    fgets(buf,BUF_LENGTH,stdin);
    char *tokenPtr = NULL;
    int i = 0;
    tokenPtr = strtok(buf,delims);

    if(strcmp(tokenPtr,"exit") == 0){

        exit(0);
    }
    else if(strcmp(tokenPtr,"cd") == 0){
        tokenPtr = strtok(NULL,delims);
        if(chdir(tokenPtr) != 0){
            printf("Path not found.\n");
        }
        getcwd(path,MAX_PATH_LENGTH);
    }
    else if(strcmp(tokenPtr,"pwd") == 0){
        printf("%s\n",path);
    }
    else {
        while(tokenPtr != NULL) {
            strArraY[i++] = tokenPtr;
            tokenPtr = strtok(NULL,delims);
        }
        execute(strArray);
    }

    bzero(strArray,sizeof(strArray)); // clears array
    printf("%s> ",path);
    fflush(stdout);
  }

}

解决方法

部分问题出在管道处理代码中 – 正如您所怀疑的那样.
else if (strcmp(argArraY[i],"|") == 0) {
    int fds[2];
    pipe(fds);
    pid_t pid;
    if ((pid = @L_607_18@) == 0) {
        dup2(fds[PIPE_WRITE],1);
        close(fds[PIPE_READ]);
        close(fds[PIPE_WRITE]);
        char** argList;
        memcpy(argList,i);
        execvp(argArray[0],argArray);            
    }
    if ((pid = @L_607_18@) == 0) {
        dup2(fds[PIPE_READ],0);
        close(fds[PIPE_READ]);
        close(fds[PIPE_WRITE]);
        execvp(argArraY[i+1],pA);            
    }
    close(fds[PIPE_READ]);
    close(fds[PIPE_WRITE]);
    wait(null);
    wait(null);
    printf("|\n");
}

一个execvp()可能是为了使用argList,因为你刚刚复制了一些材料.但是,你已经复制了i个字节,而不是我的字符指针,并且你没有确保管道被切换并用空指针替换.

@H_834_18@memcpy(argList,i * sizeof(char *)); argList[i] = 0; execvp(argList[0],argList);

请注意,这还没有验证argList上没有缓冲区溢出;请注意,没有为argList分配空间;如果你使用它,你应该在执行memcpy()之前分配内存.

或者,更简单地说,您可以不使用副本.由于您处于子进程中,因此您可以简单地使用空指针替换argArray [i],而不会影响父进程或其他子进程:

argArraY[i] = 0;
execvp(argArray[0],argArray);

您可能还会注意到execvp()的第二次调用使用了一个无法看到的变量pA;它几乎肯定是错误的初始化.作为一个适度的经验法则,你应该写:

execvp(array[n],&array[n]);

上面的调用不符合这个模式,但如果你遵循它,你就不会出错.

在每个execvp()之后,您还应该有基本的错误报告和exit(1)(或者可能是_exit(1)或_Exit(1)),这样如果子进程执行失败,子进程就不会继续. execvp()没有成功返回,但execvp()肯定会返回.

最后,对于execvp()的这些调用应该是你进行递归调用的地方.在尝试处理其他I / O重定向之前,您需要处理管道.请注意,在标准sHell中,您可以执行以下操作:

> output < input command -opts arg1 arg2

这是常规用法,但实际上是允许的.

一件好事 – 您已确保来自pipe()的原始文件描述符在所有三个进程(父级和两个子级)中都已关闭.这是你避免犯的常见错误;做得好.

大佬总结

以上是大佬教程为你收集整理的制作Linux shell时流重定向和管道全部内容,希望文章能够帮你解决制作Linux shell时流重定向和管道所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。