[英]Why does wc command in execvp() return the wrong results when taking input from a pipe in my shell?
I'm working on writing a shell in C for learning purposes and I'm trying to allow for a variable number of pipes.我正在为学习目的在 C 中编写 shell ,并且我正在尝试允许可变数量的管道。 In general, it seems to work great.
一般来说,它似乎工作得很好。 But I noticed a problem with the
wc
command.但我注意到
wc
命令有问题。
When I pipe some output of another program into wc
like ls | wc
当我把另一个程序的 pipe 一些 output 放到
wc
中时,就像ls | wc
ls | wc
it always returns ls | wc
它总是返回1 3 35
no matter what I pipe into it. 1 3 35
不管我用pipe 进去吧。 Other commands work as expected when I pipe into them.当我 pipe 进入它们时,其他命令按预期工作。 In my normal
zsh
shell wc
works fine.在我正常的
zsh
shell wc
工作正常。 I'm struggling to find the problem.我正在努力寻找问题所在。 I've tried adding
waitpid
after the forks but no dice.我尝试在分叉后添加
waitpid
,但没有骰子。
Here's the main shell loop in the main
function:这是主要 function 中的
main
shell 循环:
while (1) {
printf("\033[31;1mshell:\033[0m ");
line = read_cmds();
if (strstr(line, "|")) {
// check for pipes first
pipe_exec(line);
} else {
// we have a single command
tokens = split(line, " \t\r\n");
if (*tokens != NULL) shell_exec(tokens);
free(tokens);
}
}
Here is the function that loops through the commands:这是循环执行命令的 function:
void pipe_exec(char *line)
{
int in, status;
int pipe_no; // keep track of ptr to bring it back to free
int pfd[2];
pid_t rc;
char **cmd, **pipe_cmds;
// split takes a string and splits into array of strings based on delimiter
pipe_cmds = split(line, "|");
in = 0;
pipe_no = 0;
while (*pipe_cmds) {
cmd = split(*pipe_cmds, " \t\r\n");
if (pipe(pfd) < 0) perror("pipe");
make_proc(in, pfd[1], cmd);
close(pfd[1]);
in = pfd[0];
pipe_cmds++; // move ptr ahead one
pipe_no++;
}
// move pointer back and free
pipe_cmds -= pipe_no;
free(pipe_cmds);
rc = fork();
if (rc == 0) {
if (in != 0) dup2(in, STDIN_FILENO);
execvp(*cmd, cmd);
}
}
And then the make_proc
function that the above function calls:然后上面的
make_proc
调用的 make_proc function :
void make_proc(int in, int out, char **cmd)
{
pid_t rc;
rc = fork();
if (rc == 0) {
if (in != STDIN_FILENO) {
dup2(in, STDIN_FILENO);
close(in);
}
if (out != STDOUT_FILENO) {
dup2(out, STDOUT_FILENO);
close(out);
}
execvp(*cmd, cmd);
}
}
I took out some of the error checking to save space here.我在这里取出了一些错误检查以节省空间。 Any help is appreciated!
任何帮助表示赞赏!
You execute the last command twice and pipe its first instance to the second.您执行最后一个命令两次,pipe 它的第一个实例到第二个。 Adding something like:
添加类似:
while (*pipe_cmds) {
cmd = split(*pipe_cmds, " \t\r\n");
if (!pipe_cmds[1]) {
break;
}
if (pipe(pfd) < 0) perror("pipe");
make_proc(in, pfd[1], cmd);
close(pfd[1]);
in = pfd[0];
pipe_cmds++; // move ptr ahead one
pipe_no++;
}
would prevent the unnecessary instance, although I would rather have refactored this function a bit.会阻止不必要的实例,尽管我宁愿稍微重构一下这个 function。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.