Shell

為不同的命令重用管道數據

  • July 30, 2013

我想為不同的應用程序使用相同的管道,例如:

cat my_file | {
 cmd1
 cmd2
 cmd3
}

Cmd1 應該消耗部分輸入。Cmd2 應該消耗另一部分,依此類推。

但是,每個 cmd 都會吃掉更多的輸入,然後讀取它確實需要適當的緩衝。

例如:

yes | nl | { 
 head -n 10 > /dev/null
 cat 
} | head -n 10

從第 912 行而不是第 11 行輸出。

Tee 不是一個好的選擇,因為每個命令都應該消耗部分標準輸入。

有沒有一種簡單的方法可以讓這個工作?

您可以使用tee複制命令來通過許多命令處理整個流:

( ( seq 1 10 | tee /dev/fd/5 | sed s/^/line..\ / >&4 ) 5>&1 | wc -l ) 4>&1 
line.. 1
line.. 2
line.. 3
line.. 4
line.. 5
line.. 6
line.. 7
line.. 8
line.. 9
line.. 10
10

或使用 bash 逐行分割:

while read line ;do
   echo cmd1 $line
   read line && echo cmd2 $line
   read line && echo cmd3 $line
 done < <(seq 1 10)
cmd1 1
cmd2 2
cmd3 3
cmd1 4
cmd2 5
cmd3 6
cmd1 7
cmd2 8
cmd3 9
cmd1 10

最後有一種執行方式cmd1cmd2並且cmd3只有一次將 1/3 的流作為STDIN

( ( ( seq 1 10 |
        tee /dev/fd/5 /dev/fd/6 |
          sed -ne '1{:a;p;N;N;N;s/^.*\n//;ta;}' |
          cmd1 >&4
    ) 5>&1 |
      sed -ne '2{:a;p;N;N;N;s/^.*\n//;ta;}' |
      cmd2 >&4
 ) 6>&1 |
   sed -ne '3{:a;p;N;N;N;s/^.*\n//;ta;}' |
   cmd3 >&4
) 4>&1 
command_1: 1
command_1: 4
command_1: 7
command_1: 10
Command-2: 2
Command-2: 5
Command-2: 8
command 3: 3
command 3: 6
command 3: 9

為了嘗試這個,你可以使用:

alias cmd1='sed -e "s/^/command_1: /"' \
   cmd2='sed -e "s/^/Command_2: /"' \
   cmd3='sed -e "s/^/Command_3: /"'

如果在同一腳本上使用不同程序的一個流,您可以執行以下操作:

(
   for ((i=(RANDOM&7);i--;));do
       read line;
       echo CMD1 $line
     done
   for ((i=RANDOM&7;i--;));do
       read line
       echo CMD2 $line
     done
   while read line ;do
       echo CMD3 $line
     done
)
CMD1 1
CMD1 2
CMD1 3
CMD2 4
CMD2 5
CMD2 6
CMD2 7
CMD2 8
CMD2 9
CMD3 10

為此,您可能必須將分離的腳本轉換為bash 函式才能建構一個整體腳本。

另一種方法可能是確保每個腳本不會向STDOUT輸出任何內容,而不是在每個腳本的末尾添加 acat以便能夠連結它們:

#!/bin/sh

for ((i=1;1<n;i++));do
  read line
  pRoCeSS the $line
  echo >output_log
done

cat

最終命令可能如下所示:

seq 1 10 | cmd1 | cmd2 | cmd2

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