如何並行執行多個 pv 命令?
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()
。所以我想你應該把它當作一個功能;-)