簡體   English   中英

使用循環在 C 中管道兩個或多個 shell 命令

[英]Pipe two or more shell commands in C using a loop

我正在嘗試執行ls | wc -l ls | wc -l通過 C 中的程序,而不是使用命令行。 這是我當前的工作代碼:

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 循環?

例如:

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

    // Rewrite the 2-level pipe here

}

后來,我想擴展 for 循環來執行更多的進程,如a | b | c | ... a | b | c | ...

為了將多個命令通過管道連接在一起,您需要保持父級運行以保持每個命令的fork() ing。

使用for循環,您需要對前n - 1命令執行此操作(最后一個將在主程序中執行):

  1. 創建管道。
  2. 執行fork()
  3. 在子進程中:用前一個管道的讀端覆蓋標准輸入,用當前管道的寫端覆蓋標准輸出。
  4. 在子execve() :執行execve()
  5. 在父級中:關閉不需要的管道並保存當前管道的讀取端以供下一次迭代使用。

然后,在循環結束后,用最后一個管道的讀端覆蓋標准輸入並執行最后一個命令的execve()


下面我寫了一個簡單的工作示例來執行:

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

它應該適用於任意數量的命令(僅包括 1 個單個命令)。

注意:我沒有在這段代碼中為execvp()添加錯誤檢查只是為了使它簡短,但是你一定要在每次調用pipe()dup2()fork()和任何其他函數后檢查錯誤。

代碼:

#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\n", 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 行):

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM