Shell

如何並行執行多個 pv 命令?

  • September 28, 2018

pv我想在每個命令管道上執行一系列命令管道。這是一個例子:

for p in 1 2 3
do
 cat /dev/zero | pv -N $p | dd of=/dev/null &
done

管道中的實際命令無關緊要(cat/dd只是一個例子)……

目標是 4 個同時執行的管道,每個管道都有自己的pv輸出。但是,當我嘗試對這樣的命令進行後台處理時,pv停止並且我得到的只是 4 個停止的作業。我試過了{...|pv|...}&bash -c "...|pv|..." &結果都是一樣的。

如何同時執行多個pv命令管道?

發現我可以使用xargs以下-P選項執行此操作:

josh@subdivisions:/# seq 1 10 | xargs -P 4 -I {} bash -c "dd if=/dev/zero bs=1024 count=10000000 | pv -c -N {} | dd of=/dev/null"
       3: 7.35GiB 0:00:29 [ 280MiB/s] [                                                                                         <=>                                                                 ]
       1: 7.88GiB 0:00:29 [ 312MiB/s] [                                                                                         <=>                                                                 ]
       4: 7.83GiB 0:00:29 [ 258MiB/s] [                                                                                         <=>                                                                 ]
       2: 6.55GiB 0:00:29 [ 238MiB/s] [                                                                                         <=>                                                                 ]

發送數組的輸出以迭代到標準輸入xargs;要同時執行所有命令,請使用-P 0

pv無法在後台啟動。

正如您在原始碼的src/main/main.c文件中看到的那樣pv,他們在TOSTOP終端上設置標誌tcsetattr()(在c.c_lflag結構中termios)。他們這樣做是為了SIGTTOU在不在前台時嘗試寫入終端時接收 a,用信號處理程序擷取它,並將輸出重定向到/dev/null,以免“弄亂”終端。

/*
 * Set terminal option TOSTOP so we get signal SIGTTOU if we try to
 * write to the terminal while backgrounded.
 *
 * Also, save the current terminal attributes for later restoration.
 */
memset(&t, 0, sizeof(t));
tcgetattr(STDERR_FILENO, &t);
t_save = t;
t.c_lflag |= TOSTOP;
tcsetattr(STDERR_FILENO, TCSANOW, &t);

這當然很糟糕,因為它不僅為自己設置了該標誌,還為使用終端的所有程序設置了該標誌。

但這還不是全部。如 glibc手冊中所述:

功能: int tcsetattr (int filedes, int when, const struct termios *termios -p)

如果從其控制終端上的後台程序呼叫此函式,通常會向程序組中的所有程序發送一個 SIGTTOU 信號,就像程序試圖寫入終端一樣。例外情況是呼叫程序本身忽略或阻塞 SIGTTOU 信號,在這種情況下執行操作並且不發送信號。請參閱作業控制。

他們沒有阻止或忽略SIGTTOU. 而且他們也沒有檢查(如果他們之前設置了信號處理程序tcsetattr(),它將返回 -1 並設置errno為)的返回值。EINTR SIGTTOU

因此該過程停止。如果它收到一個SIGCONT(來自bg命令),它將在嘗試完成時再次停止tcsetattr()

所以我想你應該把它當作一個功能;-)

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