linux學習篇8--- shell,bash講解 3 數據流重導向 與 管線命令

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


數據流重導向


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 ,我們先來進行一個範例的練習:

範例一:觀察你的系統根目錄 (/) 下各目錄的文件名、權限與屬性,並記錄下來
[root@www ~]# ll /  <==此時屏幕會顯示出文件名信息

[root@www ~]# ll / > ~/rootfile <==屏幕並無任何信息
[root@www ~]# ll  ~/rootfile <==有個新檔被創建了!
-rw-r--r-- 1 root root 1089 Feb  6 17:00 /root/rootfile

文件的創建方式是:

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

/dev/null 垃圾桶黑洞裝置與特殊寫法
範例四:承範例三,將錯誤的數據丟棄,屏幕上顯示正確的數據
[dmtsai@www ~]$ find /home -name .bashrc 2> /dev/null
/home/dmtsai/.bashrc  <==只有 stdout 會顯示到屏幕上, stderr 被丟棄了

將正確與錯誤數據通通寫入同一個文件

範例五:將命令的數據全部寫入名爲 list 的文件中
[dmtsai@www ~]$ find /home -name .bashrc > list 2> list  <==錯誤
[dmtsai@www ~]$ find /home -name .bashrc > list 2>&1     <==正確
[dmtsai@www ~]$ find /home -name .bashrc &> list         <==正確

standard input : < 與 <<

將原本需要由鍵盤輸入的數據,改由文件內容來取代

範例六:利用 cat 命令來創建一個文件的簡單流程
[root@www ~]# cat > catfile
testing
cat file test
<==這裏按下 [ctrl]+d 來離開

[root@www ~]# cat catfile
testing
cat file test

由於加入 > 在 cat 後,所以那個 catfile 會被主動的創建,而內容就是剛剛鍵盤上面輸入的那兩行數據

範例七:用 stdin 取代鍵盤的輸入以創建新文件的簡單流程
[root@www ~]# cat > catfile < ~/.bashrc
[root@www ~]# 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 來複制一般!
<< 這個連續兩個小於的符號代表的是結束的輸入字符

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

[root@www ~]# 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)

[root@www ~]# ls -al /etc | less

  • 管線命令僅會處理 standard output,對於 standard error output 會予以忽略
  • 管線命令必須要能夠接受來自前一個命令的數據成爲 standard input 繼續處理才行。
擷取命令: cut, grep

[root@www ~]# cut -d'分隔字符' -f fields <==用於有特定分隔字符
[root@www ~]# cut -c 字符區間            <==用於排列整齊的信息
選項與參數:
-d  :後面接分隔字符。與 -f 一起使用;
-f  :依據 -d 的分隔字符將一段信息分割成爲數段,用 -f 取出第幾段的意思;
-c  :以字符 (characters) 的單位取出固定字符區間;

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

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

cut處理的信息是以『行』爲單位

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

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

[root@www ~]# grep [-acinv] [--color=auto] '搜尋字符串' filename
選項與參數:
-a :將 binary 文件以 text 文件的方式搜尋數據
-c :計算找到 '搜尋字符串' 的次數
-i :忽略大小寫的不同,所以大小寫視爲相同
-n :順便輸出行號
-v :反向選擇,亦即顯示出沒有 '搜尋字符串' 內容的那一行!
--color=auto :可以將找到的關鍵詞部分加上顏色的顯示喔!

範例一:將 last 當中,有出現 root 的那一行就取出來;
[root@www ~]# last | grep 'root'

範例二:與範例一相反,只要沒有 root 的就取出!
[root@www ~]# last | grep -v 'root'

範例三:在 last 的輸出信息中,只要有 root 就取出,並且僅取第一欄
[root@www ~]# last | grep 'root' |cut -d ' ' -f1
# 在取出 root 之後,利用上個命令 cut 的處理,就能夠僅取得第一欄囉!

範例四:取出 /etc/man.config 內含 MANPATH 的那幾行
[root@www ~]# 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:計算輸出的信息的整體數據

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

雙向重導向: tee

tee 會同時將數據流分送到文件去與屏幕 (screen);而輸出到屏幕的,其實就是 stdout

[root@www ~]# tee [-a] file
選項與參數:
-a  :以累加 (append) 的方式,將數據加入 file 當中!

[root@www ~]# last | tee last.list | cut -d " " -f1
# 這個範例可以讓我們將 last 的輸出存一份到 last.list 文件中;

[root@www ~]# ls -l /home | tee ~/homefile | more
# 這個範例則是將 ls 的數據存一份到 ~/homefile ,同時屏幕也有輸出信息!

字符轉換命令: tr, col, join, paste, expand

tr:

[root@www ~]# tr [-ds] SET1 ...
選項與參數:
-d  :刪除信息當中的 SET1 這個字符串;
-s  :取代掉重複的字符!

範例一:將 last 輸出的信息中,所有的小寫變成大寫字符:
[root@www ~]# last | tr '[a-z]' '[A-Z]'
# 事實上,沒有加上單引號也是可以運行的,如:『 last | tr [a-z] [A-Z] 』

範例二:將 /etc/passwd 輸出的信息中,將冒號 (:) 刪除
[root@www ~]# cat /etc/passwd | tr -d ':'

col:

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

  • paste:

這個 paste 就要比 join 簡單多了!相對於 join 必須要比對兩個文件的數據相關性, paste 就直接『將兩行貼在一起,且中間以 [tab] 鍵隔開』而已!簡單的使用方法:

[root@www ~]# paste [-d] file1 file2
選項與參數:
-d  :後面可以接分隔字符。默認是以 [tab] 來分隔的!
-   :如果 file 部分寫成 - ,表示來自 standard input 的數據的意思。


分割命令: split


參數代換: xargs


關於減號 - 的用途

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

[root@www ~]# tar -cvf - /home | tar -xvf -

上面這個例子是說:『我將 /home 裏面的文件給他打包,但打包的數據不是紀錄到文件,而是傳送到 stdout; 經過管線後,將 tar -cvf - /home 傳送給後面的 tar -xvf - 』。後面的這個 - 則是取用前一個命令的 stdout, 因此,我們就不需要使用 file 了!這是很常見的例子喔!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章