gpt4 book ai didi

c - 使用未命名管道编写我自己的 Linux shell

转载 作者:IT王子 更新时间:2023-10-29 00:33:55 25 4
gpt4 key购买 nike

我正在试验 Linux,目前正在编写一个模拟 Linux shell 的程序。

我有一个解析输入的主要功能,目前我的问题与此无关。在解析每一行之后,调用流程线方法来处理所有事情。目前,我支持常规进程、后台进程,目前正在处理仅包含 2 个命令 (cmd1 | cmd2) 的未命名管道。

代码如下:

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

void wait_for_background_process(void* arg) {
int status;
pid_t* pid = (pid_t*) arg;
do {
printf("Waiting for %d\n", *pid);
waitpid(*pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}

/************************
function: void pipeCommand(char** cmd1, char** cmd2)
comment: This pipes the output of cmd1 into cmd2.
**************************/
void pipe_command(char** cmd1, char** cmd2) {
int fds[2]; // file descriptors
if(pipe(fds) < 0) {
perror("myShell");
exit(EXIT_FAILURE);
}
pid_t pid;

pid = fork();
if(pid == 0) {
dup2(fds[1], 1);
if(execvp(cmd1[0], cmd1) < 0) {
perror("myShell");
exit(EXIT_FAILURE);
}
execvp(cmd1[0], cmd1);
} else if(pid < 0) {
perror("myShell");
exit(EXIT_FAILURE);
} else {
wait(NULL);
dup2(fds[0], 0);
if(execvp(cmd2[0], cmd2)) {
perror("myShell");
exit(EXIT_FAILURE);
}
}
}
/*
* Checks if the command is pipe command, if so we will return the
* index of the pipe
*/
int is_pipe_command(char** arglist, int count) {
int i = 0;
for(i = 0; i < count; i++) {
if(strcmp(arglist[i], "|") == 0) {
return i;
}
}
return 0;
}

int process_arglist(int count, char** arglist) {
pid_t pid;
int pipe_index;
pid = fork();
if (pid == 0) {
// Child process
if(strcmp(arglist[count-1],"&") == 0) {
char** background_arglist = (char**) malloc((count)*sizeof(char*));
if(background_arglist == NULL) {
printf("malloc failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
int i = 0;
for(i = 0; i < count - 1; i++) {
background_arglist[i] = arglist[i];
}
background_arglist[count - 1] = NULL;
if (execvp(background_arglist[0], background_arglist) == -1) {
perror("myShell");
}
} else if(pipe_index = is_pipe_command(arglist, count)) {
char** cmd1 = (char**) malloc((pipe_index+1)*sizeof(char*));
if(cmd1 == NULL) {
printf("malloc failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
int i;
int cmd1index = 0;
for(i = 0; i < pipe_index; i++) {
cmd1[cmd1index] = arglist[i];
cmd1index++;
}
cmd1[pipe_index] = NULL;
char** cmd2 = (char**) malloc((count - pipe_index)*sizeof(char*));
if(cmd2 == NULL) {
printf("malloc failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
int cmd2index = 0;
for(i = pipe_index+1; i < count; i++) {
cmd2[cmd2index] = arglist[i];
cmd2index++;
}
cmd2[count-pipe_index-1] = NULL;
pipe_command(cmd1, cmd2);
} else {
if (execvp(arglist[0], arglist) == -1) {
perror("myShell");
}
}
exit(EXIT_FAILURE);
} else if (pid < 0) {
// Error forking
perror("myShell");
exit(EXIT_FAILURE);
} else {
// Parent process
if(strcmp(arglist[count-1],"&") == 0) {
// The child is a background process
pthread_t thread;
pthread_create(&thread, NULL, wait_for_background_process, &pid);
}
else {
// Regular process
}
}

return 1;
}

我们可以关注 pipe_command 函数,它正确地获取了 2 个命令,我不明白为什么我没有得到任何输出来调用例如 ls -l |排序ls -l | grep "a".

谢谢。

最佳答案

dup 后,您需要关闭 fds[1]。否则,第二个命令进程(在您的示例中为 sortgrep)将不会从其 stdin 读取中获取 EOF .需要 EOF 以便进程知道何时停止处理并退出。

明确地说,pipe_command 中的 else block 应该有一个 close,如下所示:

} else {
wait(NULL);
dup2(fds[0], 0);
close(fds[1]); /* ADDED THIS LINE */
if(execvp(cmd2[0], cmd2)) {
perror("myShell");
exit(EXIT_FAILURE);
}
}

还有一点需要注意。通常第一个命令过程也需要一个类似的close(fds[0]);。但在您的情况下不需要它,因为第二个进程在调用 execvp 之前等待第一个进程退出,这会导致第一个进程隐式关闭其所有打开的文件描述符。

关于c - 使用未命名管道编写我自己的 Linux shell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34475830/

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