gpt4 book ai didi

无法理解我自己的 shell 中的 pipeline()

转载 作者:行者123 更新时间:2023-11-30 17:51:46 27 4
gpt4 key购买 nike

这是我为自己的 shell 找到的代码。它工作正常,但我无法理解的是代码的管道部分。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

char* cmndtkn[256];
char buffer[256];
char* path=NULL;
char pwd[128];


int main(){

//setting path variable
char *env;
env=getenv("PATH");
putenv(env);
system("clear");


printf("\t MY OWN SHELL !!!!!!!!!!\n ");
printf("_______________________________________\n\n");

while(1){

fflush(stdin);
getcwd(pwd,128);
printf("[MOSH~%s]$",pwd);
fgets(buffer,sizeof(buffer),stdin);
buffer[sizeof(buffer)-1] = '\0';

//tokenize the input command line
char* tkn = strtok(buffer," \t\n");
int i=0;
int indictr=0;



// loop for every part of the command
while(tkn!=NULL)
{

if(strcoll(tkn,"exit")==0 ){
exit(0);
}

else if(strcoll(buffer,"cd")==0){
path = buffer;
chdir(path+=3);
}

else if(strcoll(tkn,"|")==0){
indictr=i;
}

cmndtkn[i++] = tkn;
tkn = strtok(NULL," \t\n");
}cmndtkn[i]='\0';

// execute when command has pipe. when | command is found indictr is greater than 0.
if(indictr>0){

char* leftcmnd[indictr+1];
char* rightcmnd[i-indictr];
int a,b;

for(b=0;b<indictr;b++)
leftcmnd[b]=cmndtkn[b];
leftcmnd[indictr]=NULL;

for(a=0;a<i-indictr-1;a++)
rightcmnd[a]=cmndtkn[a+indictr+1];
rightcmnd[i-indictr]=NULL;

if(!fork())
{
fflush(stdout);
int pfds[2];
pipe(pfds);

if(!fork()){
close(1);
dup(pfds[1]);
close(pfds[0]);
execvp(leftcmnd[0],leftcmnd);
}
else{
close(0);
dup(pfds[0]);
close(pfds[1]);
execvp(rightcmnd[0],rightcmnd);
}
}else
wait(NULL);

//command not include pipe

}else{
if(!fork()){
fflush(stdout);
execvp(cmndtkn[0],cmndtkn);

}else
wait(NULL);
}

}

}

调用参数为 0 和 1 的 close() 的目的是什么?调用 dup() 的作用是什么?

最佳答案

在 Unix 上,dup() 调用使用编号最低的未使用文件描述符。因此,调用 dup() 之前的 close(1) 是强制 dup() 使用文件描述符 1。对于 关闭(0)

因此,别名是让进程将管道的写入端用于 stdout(文件描述符 1 用于控制台输出),并将管道的读取端用于 >stdin(文件描述符0用于控制台输入)。

使用 dup2() 代替可以更清楚地表达代码。

dup2(fd[1], 1); /* alias fd[1] to 1 */
<小时/>

根据您关于ls | 的问题sort 有效,您的问题不限于为什么进行 dup() 系统调用。您的问题实际上是 Unix 中的管道如何工作,以及 shell 命令管道如何工作。

Unix 中的管道是一对相关的文件描述符,在可写描述符上写入数据允许从可读描述符中读取该数据。 pipe() 调用以数组形式返回该对,其中第一个数组元素可读,第二个数组元素可写。

在 Unix 中,fork() 后跟某种 exec() 是生成新进程的唯一方法(还有其他库调用,例如system()popen() 创建进程,但它们调用 fork() 并执行 exec() > 在引擎盖下)。 fork() 产生一个子进程。子进程看到调用的返回值 0,而父进程看到非零返回值,该值要么是子进程的 PID,要么是 -1 > 表示发生错误。

子进程是父进程的副本。这意味着当子进程修改变量时,它正在修改驻留在其自己进程中的变量的副本。父级看不到修改发生,因为父级拥有原始副本)。但是,形成管道的一对重复的文件描述符可用于允许子进程与其父进程相互通信。

所以,ls | sort 意味着生成了两个进程,并且 ls 写入的输出被 sort 读取为输入。两个进程意味着两次调用 fork() 来创建两个子进程。一个子进程将exec()执行ls命令,另一个子进程将exec()执行sort命令。它们之间使用管道来允许进程相互通信。 ls 进程写入管道的可写端,sort 进程从管道的可读端读取。

在发出 close(1) 后,通过 dup() 调用强制 ls 进程写入管道的可写端。 sort 进程通过 close(0) 之后的 dup() 调用强制读取管道的可读端。

此外,关闭管道文件描述符的 close() 调用用于确保 ls 进程是唯一拥有打开引用的进程对于可写的 fd,sort 进程是唯一拥有对可读 fd 的开放引用的进程。该步骤很重要,因为 ls 退出后,它将关闭 fd 的可写端,并且 sort 进程将期望看到 EOF 作为结果。但是,如果其他进程仍然打开可写 fd,则不会发生这种情况。

关于无法理解我自己的 shell 中的 pipeline(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16535562/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com