鳥哥的Linux私房菜讀書筆記--管線命令pipe
注意:管線命令與連續下達命令是不一致的
管線命令只能處理由前一個指令傳來的正確資訊,也就是standard output資訊,對於standard error並沒有直接處理的能力。
每個管線的後面接的第一個資料一定是指令,該指令必須能夠接受standard input的資料,這樣的指令才可以是管線命令,例如less、more、head、tail都是可以接受standard input的管線命令,例如ls、cp、mv等不適管線命令,因為ls、cp、mv等並不會接受standard input的資料。
注意:(1)管線命令僅會處理standard output,對於standard error output會予以忽略
(2)管線命令必須要能夠接受 來自前一個指令的資料成為standard input繼續處理才行
如果我們需要硬讓standard error可以被管線命令所用,通過資料流重導向讓2>&1加入指令中就可以讓2>變成1>
1、摘取命令
<1>cut
[[email protected] ~]$ cut -d'分隔字元' -f fields <==用於有特定分隔字元 [[email protected] ~]$ cut -c 字元區間 <==用於排列整齊的訊息 選項與引數: -d :後面接分隔字元。與 -f 一起使用; -f :依據 -d 的分隔字元將一段訊息分割槽成為數段,用 -f 取出第幾段的意思; -c :以字元 (characters) 的單位取出固定字元區間;
範例二:將 export 輸出的訊息,取得第 12 字元以後的所有字串
[[email protected] ~]$ export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/home/dmtsai"
declare -x HOSTNAME="study.centos.vbird"
# 注意看,每個資料都是排列整齊的輸出!如果我們不想要『 declare -x 』時,就得這麼做:
[
cut指令是取出某部分我們想要的,而grep是分析一行資訊
[[email protected] ~]$ grep [-acinv] [--color=auto] '搜尋字串' filename 選項與引數: -a :將 binary 檔案以 text 檔案的方式搜尋資料 -c :計算找到 '搜尋字串' 的次數 -i :忽略大小寫的不同,所以大小寫視為相同 -n :順便輸出行號 -v :反向選擇,亦即顯示出沒有 '搜尋字串' 內容的那一行! --color=auto :可以將找到的關鍵詞部分加上顏色的顯示喔! 範例一:將 last 當中,有出現 root 的那一行就取出來; [[email protected] ~]$ last | grep 'root' 範例二:與範例一相反,只要沒有 root 的就取出! [[email protected] ~]$ last | grep -v 'root' 範例三:在 last 的輸出訊息中,只要有 root 就取出,並且僅取第一欄 [[email protected] ~]$ last | grep 'root' |cut -d ' ' -f1 # 在取出 root 之後,利用上個指令 cut 的處理,就能夠僅取得第一欄囉! 範例四:取出 /etc/man_db.conf 內含 MANPATH 的那幾行 [[email protected] ~]$ grep --color=auto 'MANPATH' /etc/man_db.conf MANPATH_MAP /usr/games /usr/share/man MANPATH_MAP /opt/bin /opt/man MANPATH_MAP /opt/sbin /opt/man # 神奇的是,如果加上 --color=auto 的選項,找到的關鍵詞部分會用特殊顏色顯示喔!
2、排序命令:sort、wc、uniq
<1>sort ##按照一定方式將輸出排序
[[email protected] ~]$ sort [-fbMnrtuk] [file or stdin] 選項與引數: -f :忽略大小寫的差異,例如 A 與 a 視為編碼相同; -b :忽略最前面的空格符部分; -M :以月份的名字來排序,例如 JAN, DEC 等等的排序方法; -n :使用『純數字』進行排序(預設是以文字型態來排序的); -r :反向排序; -u :就是 uniq ,相同的資料中,僅出現一行代表; -t :分隔符,預設是用 [tab] 鍵來分隔; -k :以那個區間 (field) 來進行排序的意思 範例一:個人賬號都記錄在 /etc/passwd 下,請將賬號進行排序。 [[email protected] ~]$ cat /etc/passwd | sort abrt:x:173:173::/etc/abrt:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin alex:x:1001:1002::/home/alex:/bin/bash # 鳥哥省略很多的輸出~由上面的資料看起來, sort 是預設『以第一個』資料來排序,而且預設是以『文字』型態來排序 的喔!所以由 a 開始排到最後囉!
<2>uniq ##將重複的資料僅列出一個顯示
[[email protected] ~]$ uniq [-ic] 選項與引數: -i :忽略大小寫字元的不同; -c :進行計數 範例一:使用 last 將賬號列出,僅取出賬號欄,進行排序後僅取出一位; [[email protected] ~]$ last | cut -d ' ' -f1 | sort | uniq 範例二:承上題,如果我還想要知道每個人的登入總次數呢? [[email protected] ~]$ last | cut -d ' ' -f1 | sort | uniq -c 1 6 (unknown 47 dmtsai 4 reboot 7 root 1 wtmp # 從上面的結果可以發現 reboot 有 4 次, root 登入則有 7 次!大部分是以 dmtsai 來操作! wtmp 與第一行的空白都是 last 的預設字元,那兩個可以忽略的!
<3>wc ##對檔案內容進行統計
命令:$ wc [-lwm] 選項與引數: -l :僅列出行; -w :僅列出多少字(英文單字); -m :多少字元; 範例一:那個 /etc/man_db.conf 裡面到底有多少相關字、行、字元數? [[email protected] ~]$ cat /etc/man_db.conf | wc 131 723 5171 # 輸出的三個數字中,分別代表: 『行、字數、字元數』 範例二:我知道使用 last 可以輸出登入者,但是 last 最後兩行並非賬號內容,那麼請問,我該如何以一行指令串取得登入 系統的總人次? [[email protected] ~]$ last | grep [a-zA-Z] | grep -v 'wtmp' | grep -v 'reboot' | grep -v 'unknown' |wc -l # 由於 last 會輸出空白行, wtmp, unknown, reboot 等無關賬號登入的資訊,因此,我利用grep 取出非空白行,以及去除上 述關鍵詞那幾行,再計算行數,就能夠了解囉!
3、雙向重導向(同時將資料流傳遞給檔案和螢幕)
[[email protected] ~]$ tee [-a] file 選項與引數: -a :以累加 (append) 的方式,將資料加入 file 當中!
用途:使standard output 轉存到檔案中,並將檔案內的資料顯示到螢幕上,可以使我們分析同時記錄資料,還可以作為處理資料的中間暫存檔使用。
4、字元轉換命令:tr、col、join、paste、expand
<1>tr 刪除或替換文字
[[email protected] ~]$ tr [-ds] SET1 ... 選項與引數: -d :刪除訊息當中的 SET1 這個字串; -s :取代掉重複的字元! 範例一:將 last 輸出的訊息中,所有的小寫變成大寫字元: [[email protected] ~]$ last | tr '[a-z]' '[A-Z]' # 事實上,沒有加上單引號也是可以執行的,如:『 last | tr [a-z] [A-Z] 』 範例二:將 /etc/passwd 輸出的訊息中,將冒號 (:) 刪除 [[email protected] ~]$ cat /etc/passwd | tr -d ':'
<2>col ##將tab鍵轉換為對等的空格鍵
[[email protected] ~]$ col [-xb] 選項與引數: -x :將 tab 鍵轉換成對等的空格鍵 範例一:利用 cat -A 顯示出所有特殊按鍵,最後以 col 將 [tab] 轉成空白 [[email protected] ~]$ cat -A /etc/man_db.conf <==此時會看到很多 ^I 的符號,那就是 tab [[email protected] ~]$ cat /etc/man_db.conf | col -x | cat -A | more # 嘿嘿!如此一來, [tab] 按鍵會被取代成為空格鍵,輸出就美觀多了!
<3>join ##處理兩個檔案之間的資料,對有相同資料的那一行,將他們加在一起
[[email protected] ~]$ join [-ti12] file1 file2 選項與引數: -t :join 預設以空格符分隔資料,並且比對『第一個欄位』的資料,如果兩個檔案相同,則將兩筆資料聯成一行,且 第一個欄位放在第一個! -i :忽略大小寫的差異; -1 :這個是數字的 1 ,代表『第一個檔案要用那個欄位來分析』的意思; -2 :代表『第二個檔案要用那個欄位來分析』的意思。 範例二:我們知道 /etc/passwd 第四個欄位是 GID , GID 記錄在/etc/group 當中的第三個欄位,請問如何兩個檔案整合? [[email protected] ~]# head -n 3 /etc/passwd /etc/group ==> /etc/passwd <== root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin ==> /etc/group <== root:x:0: bin:x:1: daemon:x:2: # 從上面可以看到,確實有相同的部分喔!趕緊來整合一下! [[email protected] ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3 0:root:x:0:root:/root:/bin/bash:root:x: 1:bin:x:1:bin:/bin:/sbin/nologin:bin:x: 2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x: # 同樣的,相同的欄位部分被移動到最前面了!所以第二個檔案的內容就沒再顯示。 注意:在使用join之前,需要對所處理的問津先進行排序(sort)
<4>paste ##paste直接將兩行貼在一起,且中間以tab鍵隔開
[[email protected] ~]$ paste [-d] file1 file2 選項與引數: -d :後面可以接分隔字元。預設是以 [tab] 來分隔的! - :如果 file 部分寫成 - ,表示來自 standard input 的資料的意思。
<5>expand ##將tab鍵轉換為空格鍵
[[email protected] ~]$ expand [-t] file 選項與引數: -t :後面可以接數字。一般來說,一個 tab 按鍵可以用 8 個空格鍵取代。我們也可以自行定義一個 [tab] 按鍵代表多少 個字元呢! 範例三:承上,我將 [tab] 按鍵設定成 6 個字元的話? [[email protected] ~]$ grep '^MANPATH' /etc/man_db.conf | head -n 3 | expand -t 6 - | cat -A MANPATH_MAP/bin/usr/share/man$ MANPATH_MAP/usr/bin/usr/share/man$ MANPATH_MAP/sbin/usr/share/man$ ##下劃線表示空格
5、分割槽命令:split
[[email protected] ~]$ split [-bl] file PREFIX 選項與引數: -b :後面可接欲分割槽成的檔案大小,可加單位,例如 b, k, m 等; -l :以行數來進行分割槽。 PREFIX :代表前導符的意思,可作為分割槽檔案的前導文字。 範例一:我的 /etc/services 有六百多 K,若想要分成 300K 一個檔案時? [[email protected] ~]$ cd /tmp; split -b 300k /etc/services services [[email protected] tmp]$ ll -k services* -rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesaa -rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesab -rw-rw-r--. 1 dmtsai dmtsai 55893 Jul 9 22:52 servicesac # 那個檔名可以隨意取,只要寫上前導文字,小檔案就會以xxxaa, xxxab, xxxac 等方式來建立小檔案的! 範例二:如何將上面的三個小檔案合成一個檔案,檔名為 servicesback [[email protected] tmp]$ cat services* >> servicesback # 資料流重導向
6、引數代換:xargs
x指乘號,args指arguments(引數),即產生某個指令的引數,xargs可以讀入stdin的資料,並且以空格或斷行字元作為分別,將stdin的資料分隔稱為arguments
[[email protected] ~]$ xargs [-0epn] command 選項與引數: -0 :如果輸入的 stdin 含有特殊字元,例如 `, \, 空格鍵等等字元時,這個 -0 引數可以將他還原成一般字元。 -e :這個是 EOF (end of file) 的意思。後面可以接一個字串,當 xargs 分析到這個字串時,就會停止繼續工作! -p :在執行每個指令的 argument 時,都會詢問使用者的意思; -n :後面接次數,每次 command 指令執行時,要使用幾個引數的意思。當 xargs 後面沒有接任何的指令時,預設是 以 echo 來進行輸出喔! 範例一:將 /etc/passwd 內的第一欄取出,僅取三行,使用 id 這個指令將每個賬號內容秀出來 [[email protected] ~]$ id root uid=0(root) gid=0(root) groups=0(root) # 這個 id 指令可以查詢使用者的 UID/GID 等資訊 [[email protected] ~]$ id $(cut -d ':' -f 1 /etc/passwd | head -n 3) # 雖然使用 $(cmd) 可以預先取得引數,但可惜的是, id 這個指令『僅』能接受一個引數而已! # 所以上述的這個指令執行會出現錯誤!根本不會顯示使用者的 ID 啊! [[email protected] ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | id uid=1000(dmtsai) gid=1000(dmtsai) groups=1000(dmtsai),10(wheel) # 我不是要查自己啊! # 因為 id 並不是管線命令,因此在上面這個指令執行後,前面的東西通通不見!只會執行 id! [[email protected] ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs id # 依舊會出現錯誤!這是因為 xargs 一口氣將全部的資料通通丟給 id 處理~但 id 就接受 1 個啊最多! [[email protected] ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id uid=0(root) gid=0(root) groups=0(root) uid=1(bin) gid=1(bin) groups=1(bin) uid=2(daemon) gid=2(daemon) groups=2(daemon) # 透過 -n 來處理,一次給予一個引數,因此上述的結果就 OK 正常的顯示囉! 範例二:同上,但是每次執行 id 時,都要詢問使用者是否動作? [[email protected] ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id id root ?...y uid=0(root) gid=0(root) groups=0(root) id bin ?...y # -p 的選項可以讓使用者的使用過程中,被詢問到每個指令是否執行! 範例三:將所有的 /etc/passwd 內的賬號都以 id 查閱,但查到 sync 就結束指令串 [[email protected] ~]$ cut -d ':' -f 1 /etc/passwd | xargs -e'sync' -n 1 id # 仔細與上面的案例做比較。也同時注意,那個 -e'sync' 是連在一起的,中間沒有空格鍵。上例中,第六個引數是 sync ,當下達 -e'sync' 後,則分析到 sync 這個字串時,後面的其他 stdin 的內容就會被 xargs 捨棄掉了! 使用 xargs 的原因是, 很多指令並不支援管線命令,因此我們可以透過 xargs 來提供該指令引用 standard input 之用!舉例來說,我們使用如下的範例來說明: 範例四:找出 /usr/sbin 底下具有特殊許可權的檔名,並使用 ls -l 列出詳細屬性 [[email protected] ~]$ find /usr/sbin -perm /7000 | xargs ls -l -rwx--s--x. 1 root lock 11208 Jun 10 2014 /usr/sbin/lockdev -rwsr-xr-x. 1 root root 113400 Mar 6 12:17 /usr/sbin/mount.nfs -rwxr-sr-x. 1 root root 11208 Mar 6 11:05 /usr/sbin/netreport # 聰明的讀者應該會想到使用『 ls -l $(find /usr/sbin -perm /7000) 』來處理這個範例!
7、減號- 的用途
某些檔名需要用到檔名來進行處理,該stdin與是stdout可以利用減號-來替代。