管道 (Unix)

在類Unix作業系統（以及一些其他借用了這個設計的作業系統，如Windows）中，管道（英語：Pipeline）是一系列將標準輸入輸出連結起來的行程，其中每一個行程的輸出被直接作為下一個行程的輸入。 每一個連結都由匿名管道實現。管道中的組成元素也被稱作過濾程式。
這個概念是由道格拉斯·麥克羅伊為Unix 命令列發明的，因與物理上的管道相似而得名。

簡單樣例

ls -l | less
在這個例子中，ls用於在Unix下列出目錄內容，less是一個有搜尋功能的互動式的文字分頁器。這個管線使得用戶可以在列出的目錄內容比螢幕長時目錄上下翻頁。
以less結束的管道（或more，這是個相似的分頁工具）是最常被使用的。這讓使用者可以閱覽尚未顯示的大量文字（受可用快取限制，控制台的螢幕大小、螢幕快取大小往往有限，不足以一次先輸出所有輸出內容，也不能自由捲動內容），若少了這工具則這些文字將會捲過終端機而無法閱讀到。換句話說，他們將程式設計師從為自己的軟體開發分頁器的負擔中解放了出來：他們只需要把他們的輸出用過「管道」匯入到less程式中即可，甚至也可以完全不顧分頁問題，去假定他們的用戶會在需要將輸出分頁的時候自己去這樣做。

命令列介面中的管線

所有廣泛應用於UNIX和Windows中的shell程式都有特殊的語法構建管線。典型語法是使用ASCII中的垂直線「|」（正是由於這個原因，這個符號常被稱為管道符）。當出現這樣的語法時shell會啟動各個行程，並調整各個行程的標準流之間的連接（還包括安排一些快取）。

錯誤流

通常，管線中的行程的標準錯誤流("stderr")不會通過管道傳輸；它們被合併輸出到控制台。然而，很多Shell提供一些擴充的語法去改變這一行為。比如在csh Shell和bash中，使用「|&」代替「|」來表示錯誤流也需要被合併進入標準輸出，並傳遞給下一個行程。Bourne shell也可以合併錯誤流，通過 2>&1 也可以將錯誤流重新導向到一個不同的檔案。

Pipemill

在一些常用的簡單管線中，shell僅僅只是用管道來連接每個子行程，然後在子行程中執行外部命令。因此shell本身沒有通過管線來處理資料。
然而，shell也有可能直接處理管線資料。構建這樣的語法像這樣：
command | while read var1 var2 ...; do
   # process each line, using variables as parsed into $var1, $var2, etc
   # (note that this is a subshell: var1, var2 etc will not be available
   # after the while loop terminates)
   done
... 這樣的語法叫 "pipemill" 。

匿名管道

使用C語言在UNIX中使用pipe(2)系統呼叫時，這個函式會讓系統構建一個匿名管道，這樣在行程中就開啟了兩個新的，開啟的檔案描述符：一個唯讀端和一個只寫端。管道的兩端是兩個普通的，匿名的檔案描述符，這就讓其他行程無法連接該管道。
為了避免死結並利用行程的並列執行的好處，有一個或多個管道的UNIX行程通常會呼叫fork(2)產生新行程。並且每個子行程在開始讀或寫管道之前都會關掉不會用到的管道端。或者行程會產生一個子執行緒並使用管道來讓執行緒進行資料交換。
實現程式碼：
 
#include <sys/wait.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>intmain(int argc, char *argv[]){
  int pipefd[2];
  pid_t cpid;
  char buf;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s <string>\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  if (pipe(pipefd) == -1) {
    perror("pipe");
    exit(EXIT_FAILURE);
  }

  cpid = fork();
  if (cpid == -1) {
    perror("fork");
    exit(EXIT_FAILURE);
  }

  if (cpid == 0) {    /* Child reads from pipe */
    close(pipefd[1]);          /* Close unused write end */
    while (read(pipefd[0], &buf, 1) > 0)
      write(STDOUT_FILENO, &buf, 1);

    write(STDOUT_FILENO, "\n", 1);
    close(pipefd[0]);
    _exit(EXIT_SUCCESS);

  } else {            /* Parent writes argv[1] to pipe */
    close(pipefd[0]);          /* Close unused read end */
    write(pipefd[1], argv[1], strlen(argv[1]));
    close(pipefd[1]);          /* Reader will see EOF */
    wait(NULL);                /* Wait for child */
    exit(EXIT_SUCCESS);
  }}

具名管道

具名管道可以通過呼叫mkfifo(2)或mknod(2)來構建，當被呼叫時表現為輸入或輸出的檔案。這樣可以允許建立多個管道，並且將其同標準錯誤重新導向或tee結合起來使用更為有效。
實現程式碼：
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>#include <unistd.h>int main(int argc, char *argv[]) {
  char filename[] = "test_fifo";
  if (!mkfifo(filename,S_IRUSR | S_IWUSR| S_IRGRP|S_IWGRP)){
    pid_t pid = fork();
    if (pid == 0){//child
      int fd = open(filename, O_WRONLY);
      if (fd < 0)
perror("child open()");
      else{
if (strlen(argv[1]) != write(fd, argv[1], strlen(argv[1])))
  perror("child write error");
else
  close(fd);
      }
    }
    else if (pid > 0){//father
      int fd = open(filename, O_RDONLY);
      if (fd < 0)
perror("father open()");
      else{
char buffer[200];
int readed = read(fd, buffer, 199);
close(fd);
buffer[readed] = '\0';
printf("%s\n",buffer);
      }
    }
    else
      perror("fork()");
  }
  else
    perror("mkfifo() error:");}
以上程式碼在編譯後執行時給出一個參數，子行程會將該參數內容寫入管道（該管道在目前目錄下，檔名為「test_fifo」），父行程從管道中讀取內容並顯示出來

實現

在大多數類UNIX作業系統中，管線上的所有行程同時啟動，輸入輸出流也已經被正確地連接，並且這些行程被排程程式所管理。最為重要的一點就是，所有的UNIX管道和其他管道實現不一樣的地方就是快取的概念：輸出行程可能會以每秒5000 byte的速度輸出，但是接收行程也許每秒只能接收100 byte，但不會有資料遺失。原因就是管道上游的行程的所有輸出都會被放入一個佇列中。當下游行程開始接收資料時，作業系統就會將資料從佇列傳至接收行程，並將傳完的資料從佇列中移除。當快取佇列空間不足時，上游行程會被終止，直到接收行程讀取資料為上游行程騰出空間。在Linux中，快取佇列的大小是65536 byte。

網路管線

根據Unix哲學——「一切都是檔案」，netcat和socat這樣的工具可以將管道連接到TCP/IP通訊端。

歷史

管道的概念以及垂直線的記號(|)都是由道格拉斯·麥克羅伊發明的，他是早期命令列外殼的作者。他發現他常常將一個程式的輸出作為另一個程式的輸入，於是便發明了「管道。它的想法在1973年被實現，Ken Thompson將管道添加到了UNIX作業系統。這個點子最終被移植到了其他的作業系統，比如DOS、OS/2、Microsoft Windows和BeOS，而且常常使用相同的記號(垂直線)。
雖然管道概念是獨立發展的，但是 Unix 管道相似於、也確實晚於由Ken Lochner在20世紀60年代為Dartmouth Time Sharing System開發的'communication files'。
在蘋果Automator（類似管道一樣將多個重複的命令連結起來）的那個機器人拿著一根管子的圖示也是對於最初Unix管道概念的紀念。

其他作業系統

其他作業系統的這個特色源自於Unix，例如 Taos 和 MS-DOS，最終成為軟體工程的管道與過濾器設計樣本