天天看點

linux學習篇8--- shell,bash講解 3 資料流重導向 與 管線指令

linux學習篇8---- 《鳥哥的Linux私房菜基礎學習篇(第三版)》讀書筆記

資料流重導向

linux學習篇8--- shell,bash講解 3 資料流重導向 與 管線指令

standard output 與 standard error output

标準輸出指的是『指令運作所回傳的正确的資訊』,而标準錯誤輸出可了解為『 指令運作失敗後,所回傳的錯誤資訊』

不管正确或錯誤的資料都是預設輸出到螢幕上,是以螢幕當然是亂亂的!那能不能透過某些機制将這兩股資料分開呢? 當然可以啊!那就是資料流重導向的功能啊!資料流重導向可以将 standard output (簡稱 stdout) 與 standard error output (簡稱 stderr) 分别傳送到其他的檔案或裝置去,而分别傳送所用的特殊字元則如下所示:

  1. 标準輸入  (stdin) :代碼為 0 ,使用 < 或 << ;
  2. 标準輸出  (stdout):代碼為 1 ,使用 > 或 >> ;
  3. 标準錯誤輸出(stderr):代碼為 2 ,使用 2> 或 2>> ;

為了了解 stdout 與 stderr ,我們先來進行一個範例的練習:

範例一:觀察你的系統根目錄 (/) 下各目錄的檔案名、權限與屬性,并記錄下來
[[email protected] ~]# ll /  <==此時螢幕會顯示出檔案名資訊

[[email protected] ~]# ll / > ~/rootfile <==螢幕并無任何資訊
[[email protected] ~]# ll  ~/rootfile <==有個新檔被建立了!
-rw-r--r-- 1 root root 1089 Feb  6 17:00 /root/rootfile      

檔案的建立方式是:

  1. 該檔案 (本例中是 ~/rootfile) 若不存在,系統會自動的将他建立起來
  2. 當這個檔案存在的時候,那麼系統就會先将這個檔案内容清空,然後再将資料寫入!
  3. 也就是若以 > 輸出到一個已存在的檔案中,那個檔案就會被覆寫掉!
  4. 若以>>輸出到一個檔案中,這檔案原來的内容會保留下來!

/dev/null 垃圾桶黑洞裝置與特殊寫法

範例四:承範例三,将錯誤的資料丢棄,螢幕上顯示正确的資料
[[email protected] ~]$ find /home -name .bashrc 2> /dev/null
/home/dmtsai/.bashrc  <==隻有 stdout 會顯示到螢幕上, stderr 被丢棄了      

将正确與錯誤資料通通寫入同一個檔案

範例五:将指令的資料全部寫入名為 list 的檔案中
[[email protected] ~]$ find /home -name .bashrc > list 2> list  <==錯誤
[[email protected] ~]$ find /home -name .bashrc > list 2>&1     <==正确
[[email protected] ~]$ find /home -name .bashrc &> list         <==正确      

standard input : < 與 <<

将原本需要由鍵盤輸入的資料,改由檔案内容來取代

範例六:利用 cat 指令來建立一個檔案的簡單流程
[[email protected] ~]# cat > catfile
testing
cat file test
<==這裡按下 [ctrl]+d 來離開

[[email protected] ~]# cat catfile
testing
cat file test      

由于加入 > 在 cat 後,是以那個 catfile 會被主動的建立,而内容就是剛剛鍵盤上面輸入的那兩行資料

範例七:用 stdin 取代鍵盤的輸入以建立新檔案的簡單流程
[[email protected] ~]# cat > catfile < ~/.bashrc
[[email protected] ~]# ll catfile ~/.bashrc
-rw-r--r-- 1 root root 194 Sep 26 13:36 /root/.bashrc
-rw-r--r-- 1 root root 194 Feb  6 18:29 catfile
# 注意看,這兩個檔案的大小會一模一樣!幾乎像是使用 cp 來複制一般!      

<< 這個連續兩個小于的符号代表的是結束的輸入字元

[[email protected] ~]# cat > catfile << "eof"
> This is a test.
> OK now stop
> eof  <==輸入這關鍵詞,立刻就結束而不需要輸入 [ctrl]+d

[[email protected] ~]# cat catfile
This is a test.
OK now stop     <==隻有這兩行,不會存在關鍵詞那一行!      

指令運作的判斷依據: ; , &&, ||

cmd ; cmd (不考慮指令相關性的連續指令下達)

分号前的指令運作完後就會立刻接着運作後面的指令

$? (指令回傳值) 與 && 或 ||

指令下達情況 說明
cmd1 && cmd2

1. 若 cmd1 運作完畢且正确運作($?=0),則開始運作 cmd2。

2. 若 cmd1 運作完畢且為錯誤 ($?≠0),則 cmd2 不運作。

cmd1 || cmd2

1. 若 cmd1 運作完畢且正确運作($?=0),則 cmd2 不運作。

2. 若 cmd1 運作完畢且為錯誤 ($?≠0),則開始運作 cmd2。

例題:

以 ls 測試 /tmp/vbirding 是否存在,若存在則顯示 "exist" ,若不存在,則顯示 "not exist"! ls /tmp/vbirding && echo "exist" || echo "not exist"

command1 && command2 || command3  順序不能變

管線指令 (pipe)

[[email protected] ~]# ls -al /etc | less      
  • 管線指令僅會處理 standard output,對于 standard error output 會予以忽略
  • 管線指令必須要能夠接受來自前一個指令的資料成為 standard input 繼續處理才行。

撷取指令: cut, grep

[[email protected] ~]# cut -d'分隔字元' -f fields <==用于有特定分隔字元
[[email protected] ~]# cut -c 字元區間            <==用于排列整齊的資訊
選項與參數:
-d  :後面接分隔字元。與 -f 一起使用;
-f  :依據 -d 的分隔字元将一段資訊分割成為數段,用 -f 取出第幾段的意思;
-c  :以字元 (characters) 的機關取出固定字元區間;

範例一:将 PATH 變量取出,我要找出第五個路徑。
[[email protected] ~]# echo $PATH
/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games:
# 1 |    2   |  3  |    4    |       5      |     6        |    7

[[email protected] ~]# echo $PATH | cut -d ':' -f 5
# 如同上面的數字顯示,我們是以『 : 』作為分隔,是以會出現 /usr/local/bin       

cut處理的資訊是以『行』為機關

範例二:将 export 輸出的資訊,取得第 12 字元以後的所有字元串
[[email protected] ~]# export
declare -x HISTSIZE="1000"
declare -x INPUTRC="/etc/inputrc"
declare -x KDEDIR="/usr"
declare -x LANG="zh_TW.big5"
.....(其他省略).....
# 注意看,每個資料都是排列整齊的輸出!如果我們不想要『 declare -x 』時,
# 就得這麼做:

[[email protected] ~]# export | cut -c 12-
HISTSIZE="1000"
INPUTRC="/etc/inputrc"
KDEDIR="/usr"
LANG="zh_TW.big5"
.....(其他省略).....
# 知道怎麼回事了吧?用 -c 可以處理比較具有格式的輸出資料!
# 我們還可以指定某個範圍的值,例如第 12-20 的字元,就是 cut -c 12-20 等等!      

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.config 内含 MANPATH 的那幾行
[[email protected] ~]# grep --color=auto 'MANPATH' /etc/man.config
....(前面省略)....
MANPATH_MAP     /usr/X11R6/bin          /usr/X11R6/man
MANPATH_MAP     /usr/bin/X11            /usr/X11R6/man
MANPATH_MAP     /usr/bin/mh             /usr/share/man
# 神奇的是,如果加上 --color=auto 的選項,找到的關鍵詞部分會用特殊顔色顯示喔!      

排序指令: sort, wc, uniq

sort: 

uniq:  重複的行删除掉隻顯示一個

wc:計算輸出的資訊的整體資料

[[email protected] ~]# wc [-lwm]
選項與參數:
-l  :僅列出行;
-w  :僅列出多少字(英文單字);
-m  :多少字元;      

雙向重導向: tee

tee 會同時将資料流分送到檔案去與螢幕 (screen);而輸出到螢幕的,其實就是 stdout

[[email protected] ~]# tee [-a] file
選項與參數:
-a  :以累加 (append) 的方式,将資料加入 file 當中!

[[email protected] ~]# last | tee last.list | cut -d " " -f1
# 這個範例可以讓我們将 last 的輸出存一份到 last.list 檔案中;

[[email protected] ~]# ls -l /home | tee ~/homefile | more
# 這個範例則是将 ls 的資料存一份到 ~/homefile ,同時螢幕也有輸出資訊!      

字元轉換指令: tr, col, join, paste, expand

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 ':'      

col:

[[email protected] ~]# col [-xb]
選項與參數:
-x  :将 tab 鍵轉換成對等的空格鍵
-b  :在文字内有反斜杠 (/) 時,僅保留反斜杠最後接的那個字元      
範例一:利用 cat -A 顯示出所有特殊按鍵,最後以 col 将 [tab] 轉成空白
[[email protected] ~]# cat -A /etc/man.config  <==此時會看到很多 ^I 的符号,那就是 tab
[[email protected] ~]# cat /etc/man.config | col -x | cat -A | more
# 嘿嘿!如此一來, [tab] 按鍵會被取代成為空格鍵,輸出就美觀多了!      

join:

  • paste:

這個 paste 就要比 join 簡單多了!相對于 join 必須要比對兩個檔案的資料相關性, paste 就直接『将兩行貼在一起,且中間以 [tab] 鍵隔開』而已!簡單的使用方法:

[[email protected] ~]# paste [-d] file1 file2
選項與參數:
-d  :後面可以接分隔字元。預設是以 [tab] 來分隔的!
-   :如果 file 部分寫成 - ,表示來自 standard input 的資料的意思。      

分割指令: split

參數代換: xargs

關于減号 - 的用途

管線指令在 bash 的連續的處理程式中是相當重要的!另外,在 log file 的分析當中也是相當重要的一環, 是以請特别留意!另外,在管線指令當中,常常會使用到前一個指令的 stdout 作為這次的 stdin , 某些指令需要用到檔案名 (例如 tar) 來進行處理時,該 stdin 與 stdout 可以利用減号 "-" 來替代, 舉例來說:

[[email protected] ~]# tar -cvf - /home | tar -xvf -      

上面這個例子是說:『我将 /home 裡面的檔案給他打包,但打包的資料不是紀錄到檔案,而是傳送到 stdout; 經過管線後,将 tar -cvf - /home 傳送給後面的 tar -xvf - 』。後面的這個 - 則是取用前一個指令的 stdout, 是以,我們就不需要使用 file 了!這是很常見的例子喔!

繼續閱讀