Linux tee的花式用法和pee

1.tee多重定向

tee [options] FILE1 FILE2 FILE3...

tee的做用是將一份標準輸入多重定向,一份重定向到標準輸出/dev/stdout,而後還將標準輸入重定向到每一個文件FILE中。shell

例如:bash

$ cat alpha.log | tee file1 file2 file3 | cat
$ cat alpha.log | tee file1 file2 file3 >/dev/null

上面第一個命令將alpha.log的文件內容重定向給file{1..3}和標準輸出經過管道傳遞給cat;
上面第二個命令將alpha.log的文件內容重定向給file{1..3}和/dev/null。工具

tee重定向給多個命令

寫多了腳本的人可能遇到過這樣一種需求:將一份標準輸入,重定向到多個命令中去。大概是這樣的:命令行

| CMD1
                    ↗
        INPUT | tee 
                    ↘
                      | CMD2

其實bash自身的特性就能實現這樣的需求,經過重定向到子shell中,就能模擬一個文件重定向行爲:code

cat alpha.txt | tee >(grep -E "a|b") >(grep -E "d|b|c")

(實際上這裏的兩個>(cmd_list)不是重定向,而是進程替換。命令行解析開始時,將首先進行進程替換,這兩個grep將等待標準輸入。而後啓動cat和tee,而後tee將標準輸出交給兩個進程的標準輸入)進程

上面的命令將alpha.txt文件內容重定向爲3份:一份給第一個grep命令,一份給第二個grep命令,一份給標準輸出。假如alpha.txt的內容是a b c d e5個字母分別佔用5行(每行一個字母),上面的輸出結果以下:cmd

a
b
c
d
e  # 前5行是重定向到/dev/stdout的
a
b  # 這2行是重定向給第一個grep後的執行結果
b
c
d  # 這3行是重定向給第二個grep後的執行結果

若是不想要給標準輸出的那份重定向,加上>/dev/nullio

cat alpha.txt | tee >(grep -E "a|b") >(grep -E "d|b|c") >/dev/null

tee重定向給多個命令時的問題

可是必須注意,tee將數據重定向給不一樣命令時,這些命令是獨立執行的,它們都會各自打開一個屬於本身的STDOUT,若是它們都重定向到標準輸出,因爲涉及到多個不一樣的/dev/stdout,它們的結果將出現兩個問題:file

  1. 不保證有序性
  2. 由於跨了命令,交互式模式下(默認標準輸出爲屏幕)可能會出現命令行隔斷的問題(非交互式下不會有問題)

例如:語法

$ cat alpha.txt | tee >(grep -E "a|b") >(grep -E "d|b|c") >/dev/null
$ a     # 結果直接出如今提示符所在行
b
b
c
d

$ cat alpha.txt | tee >(grep -E "a|b") >(grep -E "d|b|c") >/dev/null
b
c      # 此次的結果和上次的順序不同
d
a
b

這兩個問題,在寫腳本過程當中必須解決。

對於第二個問題:不一樣/dev/stdout同時輸出時在屏幕上交叉輸出的問題,只需將它們再次重定向走便可,這樣兩份不一樣的/dev/stdout都再次同時做爲一份標準輸入:

$ cat alpha.txt | tee >(grep -E "a|b") >(grep -E "d|b|c") >/dev/null | cat

對於第一個問題:不一樣/dev/stdout同時輸出時,輸出順序的隨機性,這個沒有好方法,只能在各命令行中將各自的結果保存到文件中:

$ cat alpha.txt | tee >(grep -E "a|b" >file1) >(grep -E "d|b|c" >file2) >/dev/null

因此,tee在重定向到多個命令中是有缺陷的,或者說用起來很是不方便,只要將各命令的結果各自保存時,才能一切按照本身的預期進行。那麼,pee登場了,多重定向很是好用的一個命令。

2.pee代替tee

pee是moreutils包中的一個小工具,先安裝它(epel源中有):

yum -y install moreutils

在man pee中,pee的做用是將標準輸入tee給管道。語法:

pee ["cmds"]

不是很好理解,能夠經過幾個示例直接感覺它的用法。

$ cat alpha.txt | pee 'grep -E "a|b"' 'grep -E "d|b|c"'
a
b
b
c
d

因此,它的基本用法是pee "CMD1" "CMD2"

若是想將結果保存到文件,只需加一個命令便可,例以下面的cat >myfile

$ cat alpha.txt | pee 'grep -E "a|b"' 'grep -E "d|b|c"' 'cat >myfile'

和tee有一樣的問題,若是各命令都沒有指定本身的標準輸出重定向,它們將各自打開一個屬於本身的/dev/stdout,一樣會有多個/dev/stdout同時輸出時結果數據順序隨機性的問題,可是不會有多個/dev/stdout同時輸出時交互式的隔斷性問題,由於pee會收集各個命令的標準輸出,而後將收集的結果做爲本身的標準輸出

pee和tee最大的不一樣,在於pee未來自多個不一樣命令的結果做爲pee本身的標準輸出,因此下面的命令是能夠像普通命令同樣進行重定向的。

INPUT | pee CMD1 CMD2 >/FILE

而tee則不一樣,是將cmd1和cmd2的結果放進標準輸出(假設各命令自身沒有使用重定向),保存到FILE中的是tee讀取的標準輸入。

INPUT | tee >(cmd1) >(cmd2) >/FILE

因此,想要重定向tee中cmd1和cmd2的總結果,必須使用額外的管道,或者將整個tee放進子shell。

INPUT | tee >(cmd1) >(cmd2) >/dev/null | cat >FILE1
INPUT | ( tee >(cmd1) >(cmd2) >/dev/null ) >/FILE1
相關文章
相關標籤/搜索