Shell-Script

Shell:兩個命令的STDIN/STDOUT的相互管道

  • August 15, 2021

當我們使用 POSIX shell 執行它時,

$ cmd0 | cmd1

cmd0 的 STDOUT 通過管道傳送到 cmd1 的 STDIN。

問:除此之外,如何將 cmd1 的 STDOUT也通過管道傳輸到 cmd0 的 STDIN?

是否必須使用從/到命名管道(FIFO)的重定向?我不太喜歡命名管道,因為它們佔用了一些文件系統路徑,我需要擔心名稱衝突。還是我必須通過 C、Python 或一些通用程式語言呼叫 pipe(2)?

(cmd0 和 cmd1 都做一些網路 I/O,所以它們不會永遠互相阻塞。)

在具有雙向管道(不是 Linux)的系統上,您可以執行以下操作:

cmd0 <&1 | cmd1 >&0

在 Linux 上,您可以執行以下操作:

: | { cmd1 | cmd2; } > /dev/fd/0

這是有效的,因為在 Linux(和 Cygwin,但通常不是其他系統)/dev/fd/x上,x管道(命名或未命名)的 fd 就像命名管道一樣,也就是說,以讀取模式打開它可以獲得讀取端和寫入模式讓你寫作結束。

使用yashshell及其x>>|y 管道重定向運算符

{ cmd0 | cmd1; } >>|0

使用帶有 coproc 支持的外殼

  • zsh:
  coproc cmd0
  cmd1 <&p >&p
  • 克什
  cmd0 |&
  cmd1 <&p >&p
  • bash4+
  coproc cmd0
  cmd1 <&"${COPROC[0]}" >&"${COPROC[1]}"

專用工具方法(無恥地從這個非常相似的問題的答案中複製):

使用pipexec

pipexec [ A /path/to/cmd0 ] \
       [ B /path/to/cmd1 ] \
       '{A:1>B:0}' '{A:0>B:1}'

或使用dpipe

dpipe cmd0 = cmd1

或使用socat

socat EXEC:cmd0 EXEC:cmd1,nofork                 # using socketpairs
socat EXEC:cmd0,commtype=pipes EXEC:cmd1,nofork  # using pipes

我不知道python,但這也相對容易完成perl

perl -e 'pipe STDOUT,STDIN; exec "cmd0 | cmd1"'

您也可以隨時使用命名管道,但是為它們找到唯一的名稱以及在其中創建它們的一些安全目錄,限制對它們的訪問(因此其他程序無法打開它們並進行干預)以及之後的清理成為難以解決的額外問題可靠且便攜地克服。

無論如何,當心死鎖!

引用自:https://unix.stackexchange.com/questions/296432