使用循环在 C 中管道两个或多个 shell 命令 [英] Pipe two or more shell commands in C using a loop

查看:14
本文介绍了使用循环在 C 中管道两个或多个 shell 命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试执行 ls |wc -l 通过 C 中的程序,而不是使用命令行.这是我当前的工作代码:

I'm trying to execute ls | wc -l through a program in C, instead of using the command line. This is my current working code:

int main() { 
   int pfds[2]; 
   pipe(pfds); 
   pid_t pid = fork(); 
   if ( pid == 0 ) { /* The child process*/ 
      close(1);
      dup(pfds[1]);
      close(pfds[0]);
      execlp("ls", "ls", NULL); 
   } else { /* The parent process*/ 
      close(0);
      dup(pfds[0]);
      close(pfds[1]);
      wait(0);
      execlp("wc", "wc", "-l", NULL); 
   } 
   return 0; 
}

如何重写此代码以使用 for 循环?

How would I rewrite this code to work with a for-loop?

例如:

for (i=0; i<2; i++) {

    // Rewrite the 2-level pipe here

}

稍后,我想扩展 for 循环以执行更多的进程,例如 a |乙 |c |...

Later, I would like to extend the for loop to execute more processes piped together like a | b | c | ...

推荐答案

为了将多个命令连接在一起,您需要保持父级运行以保持每个命令的 fork()ing.

In order to pipe multiple commands together, you'll need to keep the parent running to keep fork()ing for each command.

使用 for 循环,您需要对第一个 n - 1 命令执行此操作(最后一个将在主程序中执行):

Using a for loop, you will need to do this for the first n - 1 commands (the last one will be executed in the main program):

  1. 创建管道.
  2. 执行fork().
  3. 在孩子中:用上一个管道的读端覆盖标准输入,用当前管道的写端覆盖标准输出.
  4. 在子进程中:执行 execve().
  5. 在父级中:关闭不需要的管道并保存当前管道的读取端以用于下一次迭代.
  1. Create a pipe.
  2. Execute fork().
  3. In the child: overwrite standard input with the read end of the previous pipe, and standard output with the write end of the current pipe.
  4. In the child: execute execve().
  5. In the parent: close unneeded pipes and save read end of current pipe to be used in the next iteration.

然后,循环结束后,用最后一个管道的读取端覆盖标准输入,并执行最后一个命令的execve().

Then, after the loop ends, overwrite standard input with the read end of the last pipe and execute execve() of the last command.

下面我写了一个简单的执行示例:

Below I've written a simple working example that executes:

ls | wc -l | xargs printf "0x%x
" | cowsay

它应该适用于任意数量的命令(包括仅 1 个单个命令).

It should work for any number of commands (including only 1 single command).

注意:为了简短起见,我没有在此代码中为 execvp() 添加错误检查,但您绝对应该在每次调用后检查错误pipe()dup2()fork() 和任何其他函数.

NOTE: I did not add error checks in this code apart for execvp() just to make it short, but you should definitely check for errors after each call to pipe(), dup2(), fork() and any other function.

代码:

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

#define MAX_ARGC 3

int main(void) {
    char *commands[][MAX_ARGC + 1] = {
        {"ls", NULL},
        {"wc", "-l", NULL},
        {"xargs", "printf", "0x%x
", NULL},
        {"cowsay", NULL}
    };

    size_t i, n;
    int prev_pipe, pfds[2];

    n = sizeof(commands) / sizeof(*commands);
    prev_pipe = STDIN_FILENO;

    for (i = 0; i < n - 1; i++) {
        pipe(pfds);

        if (fork() == 0) {
            // Redirect previous pipe to stdin
            if (prev_pipe != STDIN_FILENO) {
                dup2(prev_pipe, STDIN_FILENO);
                close(prev_pipe);
            }

            // Redirect stdout to current pipe
            dup2(pfds[1], STDOUT_FILENO);
            close(pfds[1]);

            // Start command
            execvp(commands[i][0], commands[i]);

            perror("execvp failed");
            exit(1);
        }

        // Close read end of previous pipe (not needed in the parent)
        close(prev_pipe);

        // Close write end of current pipe (not needed in the parent)
        close(pfds[1]);

        // Save read end of current pipe to use in next iteration
        prev_pipe = pfds[0];
    }

    // Get stdin from last pipe
    if (prev_pipe != STDIN_FILENO) {
        dup2(prev_pipe, STDIN_FILENO);
        close(prev_pipe);
    }

    // Start last command
    execvp(commands[i][0], commands[i]);

    perror("execvp failed");
    exit(1);
}

我机器上的输出(因为 ls 返回 41 == 0x29 行):

Output on my machine (since ls returned 41 == 0x29 lines):

 ______
< 0x29 >
 ------
           ^__^
           (oo)\_______
            (__)       )/
                ||----w |
                ||     ||

这篇关于使用循环在 C 中管道两个或多个 shell 命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆