Chinaunix首页 | 论坛 | 博客
  • 博客访问: 497909
  • 博文数量: 78
  • 博客积分: 1771
  • 博客等级: 上尉
  • 技术积分: 944
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-25 10:20
文章分类

全部博文(78)

文章存档

2014年(2)

2013年(10)

2012年(9)

2011年(7)

2010年(11)

2009年(10)

2008年(12)

2007年(17)

我的朋友

分类:

2007-04-28 17:29:19

雙向重導向: tee
想個簡單的東西,我們由前一節知道 > 會將資料流整個傳送給檔案或裝置, 因此我們除非去讀取該檔案或裝置,否則就無法繼續利用這個資料流。 萬一我想要將這個資料流的處理過程中,將某段訊息存下來,應該怎麼做?呵呵! 利用 tee 就可以囉~我們可以這樣簡單的看一下:
 
圖五、tee 的工作流程
同時將資料流分送到檔案去與螢幕 (screen);而輸出到螢幕的,其實就是 stdout ,可以讓下個指令繼續處理喔!
[root@linux ~]# tee [-a] file
參數:
-a  :以累加 (append) 的方式,將資料加入 file 當中!
範例:
[root@linux ~]# last | tee last.list | cut -d " " -f1
# 這個範例可以讓我們將 last 的輸出存一份到 last.list 檔案中;
[root@linux ~]# ls -l /home | tee ~/homefile | more
# 這個範例則是將 ls 的資料存一份到 ~/homefile ,同時螢幕也有輸出訊息!
[root@linux ~]# ls -l / | tee -a ~/homefile | more
# 要注意: tee 後接的檔案會被覆蓋,所以,我們要加上 -a
# 這個參數才能將訊息累加。
 
有沒有發現在命令重導向的時候,如果我們要將資料送出到檔案的時候, 螢幕上就不會出現任何的資料!那麼如果我們需要將資料同時顯示在螢幕上跟檔案中呢?呵呵!這個時候就需要 tee 這個指令囉!使用 last 可以查看到這個月份的登入資料,而使用了 tee 之後,會將資料同時傳給下一個命令去執行,也會將資料寫入 last.list 這個檔案中!也是個好幫手!
 
--------------------------------------------------------------------------------
字元轉換命令: tr, col, join, paste, expand
我們在 vi 文書處理器 章節當中,提到過 DOS 斷行字元與 Unix 斷行字元的不同, 並且可以使用 dos2unix 與 unix2dos 來完成轉換。好了,那麼思考一下,是否還有其他常用的字元替代? 舉例來說,要將大寫改成小寫,或者是 [tab] 按鍵轉成空白鍵?還有,如何將兩篇訊息整合成一篇? 底下我們就來介紹一下這些字元轉換命令在管線當中的使用方法:

--------------------------------------------------------------------------------
tr
tr 可以用來刪除一段訊息當中的文字,或者是進行文字訊息的替換!
[root@linux ~]# tr [-ds] SET1 ...
參數:
-d  :刪除訊息當中的 SET1 這個字串;
-s  :取代掉重複的字元!
範例:
範例一:將 last 輸出的訊息中,所有的小寫變成大寫字元:
[root@linux ~]# last | tr '[a-z]' '[A-Z]'
範例二:將 /etc/passwd 輸出的訊息中,將冒號 (:) 刪除
[root@linux ~]# cat /etc/passwd | tr -d ':'
範例三:將 DOS 檔案的斷行字元 ^M 符號刪除:
[root@linux ~]# cat /home/test/dostxt | tr -d '\r' > dostxt-noM
# 那個 \r 指的是 DOS 的斷行字元,關於更多的字符,請參考 man tr
 
其實這個指令也可以寫在『正規表示法』裡頭!因為他也是由正規表示法的方式來取代資料的! 以上面的例子來說,使用 [] 可以設定一串字呢! 也常常用來取代檔案中的怪異符號! 例如上面第三個例子當中,可以去除 DOS 檔案留下來的 ^M 這個斷行的符號!這東西相當的有用!相信處理 Linux & Windows 系統中的人們最麻煩的一件事就是這個事情啦!亦即是 DOS 底下會自動的在每行行尾加入 ^M 這個斷行符號!這個時候我們可以使用這個 tr 來將 ^M 去除! ^M 可以使用 \r 來代替之!
 
--------------------------------------------------------------------------------
col
[root@linux ~]# col [-x]
參數:
-x  :將 tab 鍵轉換成對等的空白鍵
範例:
[root@linux ~]# cat -A /etc/man.config  <==此時會看到很多 ^I 的符號,那就是 tab
[root@linux ~]# cat /etc/man.config | col -x | cat -A | more
# 嘿嘿!如此一來, [tab] 按鍵會被取代成為空白鍵,輸出就美觀多了!
 
雖然 col 有他特殊的用途,不過,很多時候,他可以用來簡單的處理將 [tab] 按鍵取代成為空白鍵! 例如上面的例子當中,如果使用 cat -A 則 [tab] 會以 ^I 來表示。 但經過 col -x 的處理,則會將 [tab] 取代成為對等的空白鍵!
 
--------------------------------------------------------------------------------
join
join 看字面上的意義 (加入/參加) 就可以知道,他是在處理兩個檔案之間的資料, 而且,主要是在處理『兩個檔案當中,有 "相同資料" 的那一行,將他加在一起』的意思。我們利用底下的簡單例子來說明:
[root@linux ~]# join [-ti12] file1 file2
參數:
-t  :join 預設以空白字元分隔資料,並且比對『第一個欄位』的資料,
      如果兩個檔案相同,則將兩筆資料聯成一行,且第一個欄位放在第一個!
-i  :忽略大小寫的差異;
-1  :這個是數字的 1 ,代表『第一個檔案要用那個欄位來分析』的意思;
-2  :代表『第二個檔案要用那個欄位來分析』的意思。
範例:
範例一:用 root 的身份,將 /etc/passwd 與 /etc/shadow 相關資料整合成一欄
[root@linux ~]# join -t ':' /etc/passwd /etc/shadow
bin:x:1:1:bin:/bin:/sbin/nologin:*:12959:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:12959:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin:*:12959:0:99999:7:::
# 因為 /etc/shadow 的權限問題,所以這裡必須是 root 才能動作!而 /etc/passwd
# 與 /etc/shadow 都是以 : 來分隔欄位,所以必須要使用 -t ':' 規範欄位分隔字元。
# 且,因為 /etc/shadow 與 /etc/passwd 剛好都是以第一個欄位為帳號名稱,所以,
# 就可以將同一行的資料給他貼在一起了!
# 另外,再仔細看一下 /etc/shadow 的內容與 /etc/passwd 的內容,您會發現,
# 兩者都以帳號為開始,而上面的輸出資料中您會發現特殊字體部分,那代表
# 第二個檔案的內容。在第二個檔案的內容部分,由於帳號(第一個欄位)與
# 第一的檔案是相同的,所以當然就省略掉,因此就成為上面的輸出。
範例二:我們知道 /etc/passwd 第四個欄位是 GID ,那個 GID 記錄在
        /etc/group 當中的第三個欄位,請問如何將兩個檔案整合?
[root@linux ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:root,bin,daemon
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:root,bin,daemon
4:adm:x:3:adm:/var/adm:/sbin/nologin:adm:x:root,adm,daemon
# 這個例子就更明顯了!原本的 /etc/passwd 的第一行內容應該是:
# root:x:0:0:root:/root:/bin/bash
# 至於 /etc/group 第一行內容應該是:
# root:x:0:
# 我將第一個檔案的第四欄與第二個檔案的第三欄取出,放置到輸出的最前方,
# 然後將剩下的資料給他加在一起!就成了上面的輸出啦!
 
這個 join 在處理兩個相關的資料檔案時,就真的是很有幫助的啦! 例如上面的案例當中,我的 /etc/passwd, /etc/shadow, /etc/group 都是有相關性的, 其中 /etc/passwd, /etc/shadow 以帳號為相關性,至於 /etc/passwd, /etc/group 則以所謂的 GID (帳號的數字定義) 來作為他的相關性。根據這個相關性, 我們可以將有關係的資料放置在一起!這在處理資料可是相當有幫助的! 但是上面的例子有點難,希望您可以靜下心好好的看一看原因喔!
此外,需要特別注意的是,在使用 join 之前,你所需要處理的檔案應該要事先經過排序 (sort) 處理! 否則有些比對的項目會被略過呢!特別注意了!
 
--------------------------------------------------------------------------------
paste
這個 paste 就要比 join 簡單多了!相對於 join 必須要比對兩個檔案的資料相關性, paste 就直接『將兩行貼在一起,且中間以 [tab] 鍵隔開』而已!簡單的使用方法:
[root@linux ~]# paste [-d] file1 file2
參數:
-d  :後面可以接分隔字元。預設是以 [tab] 來分隔的!
-   :如果 file 部分寫成 - ,表示來自 standard input 的資料的意思。
範例:
範例一:將 /etc/passwd 與 /etc/shadow 同一行貼在一起
[root@linux ~]# paste /etc/passwd /etc/shadow
bin:x:1:1:bin:/bin:/sbin/nologin        bin:*:12959:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:12959:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin    adm:*:12959:0:99999:7:::
# 注意喔!同一行中間是以 [tab] 按鍵隔開的!
範例二:先將 /etc/group 讀出(用 cat),然後與範例一貼上一起!且僅取出前三行
[root@linux ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3
# 這個例子的重點在那個 - 的使用!那玩意兒常常代表 stdin 喔!
 
 
--------------------------------------------------------------------------------
expand
這玩意兒就是在將 [tab] 按鍵轉成空白鍵啦~可以這樣玩:
[root@linux ~]# expand [-t] file
參數:
-t  :後面可以接數字。一般來說,一個 tab 按鍵可以用 8 個空白鍵取代。
      我們也可以自行定義一個 [tab] 按鍵代表多少個字元呢!
範例:
範例一:將 /etc/man.config 內行首為 MANPATH 的字樣就取出;僅取前三行;
[root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3
MANPATH /usr/man
MANPATH /usr/share/man
MANPATH /usr/local/man
# 行首的代表標誌為 ^ ,這個我們留待下節介紹!先有概念即可!
範例二:承上,如果我想要將所有的符號都列出來?(用 cat)
[root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3 |cat -A
MANPATH^I/usr/man$
MANPATH^I/usr/share/man$
MANPATH^I/usr/local/man$
# 發現差別了嗎?沒錯~ [tab] 按鍵可以被 cat -A 顯示成為 ^I
範例三:承上,我將 [tab] 按鍵設定成 6 個字元的話?
[root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3 | \
>  expand -t 6 - | cat -A
MANPATH     /usr/man$
MANPATH     /usr/share/man$
MANPATH     /usr/local/man$
123456123456123456.....
# 仔細看一下上面的數字說明,因為我是以 6 個字元來代表一個 [tab] 的長度,所以,
# MAN... 到 /usr 之間會隔 12 (兩個 [tab]) 個字元喔!如果 tab 改成 9 的話,
# 情況就又不同了!這裡也不好理解~您可以多設定幾個數字來查閱就曉得!
 
expand 也是挺好玩的~他會自動將 [tab] 轉成空白鍵~所以,以上面的例子來說, 使用 cat -A 就會查不到 ^I 的字符囉~此外,因為 [tab] 最大的功能就是格式排列整齊! 我們轉成空白鍵後,這個空白鍵也會依據我們自己的定義來增加大小~ 所以,並不是一個 ^I 就會換成 8 個空白喔!這個地方要特別注意的哩! 此外,您也可以參考一下 unexpand 這個將空白轉成 [tab] 的指令功能啊! ^_^

--------------------------------------------------------------------------------
分割命令: split
如果你有檔案太大,導致一些攜帶式裝置無法複製的問題,嘿嘿!找 split 就對了! 他可以幫你將一個大檔案,依據檔案大小或行數來分割,就可以將大檔案分割成為小檔案了! 快速又有效啊!真不錯~
[root@linux ~]# split [-bl] file PREFIX
參數:
-b  :後面可接欲分割成的檔案大小,可加單位,例如 b, k, m 等;
-l  :以行數來進行分割。
範例:
範例一:我的 /etc/termcap 有七百多K,若想要分成 300K 一個檔案時?
[root@linux ~]# cd /tmp; split -b 300k /etc/termcap termcap
[root@linux tmp]# ls -l termcap*
-rw-rw-r--  1 root root  307200  8月 17 00:25 termcapaa
-rw-rw-r--  1 root root  307200  8月 17 00:25 termcapab
-rw-rw-r--  1 root root  184848  8月 17 00:25 termcapac
# 那個檔名可以隨意取的啦!我們只要寫上前導文字,小檔案就會以
# xxxaa, xxxab, xxxac 等方式來建立小檔案的!
範例二:如何將上面的三個小檔案合成一個檔案,檔名為 termcapback
[root@linux tmp]# cat termcap* >> termcapback
# 很簡單吧?就用資料流重導向就好啦!簡單!
範例三:使用 ls -al / 輸出的資訊中,每十行記錄成一個檔案
[root@linux tmp]# ls -al / | split -l 10 - lsroot
# 重點在那個 - 啦!一般來說,如果需要 stdout/stdin 時,但偏偏又沒有檔案,
# 有的只是 - 時,那麼那個 - 就會被當成 stdin 或 stdout ~
 
在 Windows 的情況下,你要將檔案分割需要如何作?!傷腦筋吧!呵呵!在 Linux 底下就簡單的多了!你要將檔案分割的話,那麼就使用 -b size 來將一個分割的檔案限制其大小,如果是行數的話,那麼就使用 -l line 來分割!好用的很!如此一來,你就可以輕易的將你的檔案分割成 floppy 的大小,方便你 copy 囉!
 
--------------------------------------------------------------------------------
參數代換: xargs
xargs 是在做什麼的呢?就以字面上的意義來看, x 是加減乘除的乘號,args 則是 arguments (參數) 的意思,所以說,這個玩意兒就是在產生某個指令的參數的意思! xargs 可以讀入 stdin 的資料,並且以空白字元或斷行字元作為分辨,將 stdin 的資料分隔成為 arguments 。 因為是以空白字元作為分隔,所以,如果有一些檔名或者是其他意義的名詞內含有空白字元的時候, xargs 可能就會誤判了~他的用法其實也還滿簡單的!就來看一看先!
[root@linux ~]# xargs [-0epn] command
參數:
-0  :如果輸入的 stdin 含有特殊字元,例如 `, \, 空白鍵等等字元時,這個 -0 參數
      可以將他還原成一般字元。這個參數可以用於特殊狀態喔!
-e  :這個是 EOF (end of file) 的意思。後面可以接一個字串,當 xargs 分析到
      這個字串時,就會停止繼續工作!
-p  :在執行每個指令的 argument 時,都會詢問使用者的意思;
-n  :後面接次數,每次 command 指令執行時,要使用幾個參數的意思。看範例三。
當 xargs 後面沒有接任何的指令時,預設是以 echo 來進行輸出喔!
範例:
範例一:將 /etc/passwd 內的第一欄取出,僅取三行,使用 finger 這個指令將每個
        帳號內容秀出來
[root@linux ~]# cut -d':' -f1 < /etc/passwd |head -n 3| xargs finger
Login: root                             Name: root
Directory: /root                        Shell: /bin/bash
Never logged in.
No mail.
No Plan.
......底下省略.....
# 由 finger account 可以取得該帳號的相關說明內容,例如上面的輸出就是 finger root
# 後的結果。在這個例子當中,我們利用 cut 取出帳號名稱,用 head 取出三個帳號,
# 最後則是由 xargs 將三個帳號的名稱變成 finger 後面需要的參數!
範例二:同上,但是每次執行 finger 時,都要詢問使用者是否動作?
[root@linux ~]# cut -d':' -f1 < /etc/passwd |head -n 3| xargs -p finger
finger root bin daemon ?...y
......底下省略.....
# 呵呵!這個 -p 的參數有趣了吧?!他可以讓使用者的使用過程中,被詢問到每個
# 指令是否執行!
範例三:將所有的 /etc/passwd 內的帳號都以 finger 查閱,但一次僅查閱五個帳號
[root@linux ~]# cut -d':' -f1 < /etc/passwd | xargs -p -n 5 finger
finger root bin daemon adm lp ?...y
......底下省略.....
# 在這裡鳥哥使用了 -p 這個參數來讓您對於 -n 更有概念。一般來說,某些指令後面
# 可以接的 arguments 是有限制的,不能無限制的累加,此時,我們可以利用 -n
# 來幫助我們將參數分成數個部分,每個部分分別再以指令來執行!這樣就 OK 啦!^_^
[root@linux ~]#
範例四:同上,但是當分析到 lp 就結束這串指令?
[root@linux ~]# cut -d':' -f1 < /etc/passwd | xargs -p -e'lp' finger
finger root bin daemon adm ?...
# 仔細與上面的案例做比較。也同時注意,那個 -e'lp' 是連在一起的,中間沒有空白鍵。
# 上個例子當中,第五個參數是 lp 啊,那麼我們下達 -e'lp' 後,則分析到 lp
# 這個字串時,後面的其他 stdin 的內容就會被 xargs 捨棄掉了!
 
其實,在 man xargs 裡面就有三四個小範例,您可以自行參考一下內容。 此外, xargs 真的是很好用的一個玩意兒!您真的需要好好的參詳參詳!
 
--------------------------------------------------------------------------------
關於減號 - 的用途
管線命令在 bash 的連續的處理程序中是相當重要的!另外,在 log file 的分析當中也是相當重要的一環, 所以請特別留意!另外,在管線命令當中,常常會使用到前一個指令的 stdout 作為這次的 stdin , 某些指令需要用到檔案名稱 (例如 tar) 來進行處理時,該 stdin 與 stdout 可以利用減號 "-" 來替代, 舉例來說:
[root@linux ~]# tar -cvf - /home | tar -xvf -
 
上面這個例子是說:『我將 /home 裡面的檔案給他打包,但打包的資料不是紀錄到檔案,而是傳送到 stdout; 經過管線後,將 tar -cvf - /home 傳送給後面的 tar -xvf - 』。後面的這個 - 則是取用前一個指令的 stdout, 因此,我們就不需要使用 file 了!這是很常見的例子喔!注意注意!
--------------------------------------------------------------------------------
本章習題練習
( 要看答案請將滑鼠移動到『答:』底下的空白處,按下左鍵圈選空白處即可察看 )
在 Linux 上可以找到哪些 shell(舉出三個) ?那個檔案記錄可用的 shell ?而 Linux 預設的 shell 是?
1) /bin/bash, /bin/tcsh, /bin/csh
2) /etc/shells
3) bash ,亦即是 /bin/bash。
在 shell 環境下,有個提示字元 (prompt),他可以修改嗎?要改什麼?預設的提示字元內容是?
可以修改的,改 PS1 這個變數,這個 PS1 變數的預設內容為:『[\u@\h \W]\$』
如何顯示 HOME 這個環境變數?
echo $HOME
如何得知目前的所有變數與環境變數的設定值?
環境變數用 env 而所有變數用 set 即可顯示
我是否可以設定一個變數名稱為 3myhome ?
不行!變數不能以數字做為開頭,參考變數設定規則的內容
在這樣的練習中『A=B』且『B=C』,若我下達『unset $A』,則取消的變數是 A 還是 B?
被取消的是 B 喔,因為 unset $A 相當於 unset B 所以取消的是 B ,A 會繼續存在!
如何取消變數與命令別名的內容?
使用 unset 及 unalias 即可
如何設定一個變數名稱為 name 內容為 It's my name ?
name=It\'s\ my\ name 或 name="It's my name"
環境變數檔案的載入順序?
先由 /etc/passwd 取得 bash 這個 shell ,再到 /etc/profile 讀取主要的環境變數,同時亦會將 /etc/inputrc 及 /etc/profile.d 內容均讀入。之後,再到個人的家目錄讀取 ~/.bash_profile 及 ~/.bashrc 等檔案!
man page 的路徑設定檔案?
/etc/man.config 或 /etc/man.conf
試說明 ', ", 與 ` 這些符號在變數定義中的用途?
參考變數規則那一章節,其中, " 可以具有變數的內容屬性, ' 則僅有一般字元,至於 ` 之內則是可先被執行的指令。
跳脫符號 \ 有什麼用途?
可以用來跳脫特殊字元,例如 Enter, $ 等等,使成為一般字元!
連續命令中, ;, &&, || 有何不同?
分號可以讓兩個 command 連續運作,不考慮 command1 的輸出狀態, && 則前一個指令必需要沒有錯誤訊息,亦即回傳值需為 0 則 command2 才會被執行, || 則與 && 相反!
如何將 last 的結果中,獨立出帳號,並且印出本月份曾經登入過的帳號?
 last | cut –d “ “ –f1 | sort | uniq
請問 foo1 && foo2 | foo3 > foo4 ,這個指令串當中, foo1/foo2/foo3/foo4 是指令還是檔案? 整串指令的意義為?
foo1/foo2 與 foo3 都是指令, foo4 是裝置或檔案。整串指令意義為:
當 foo1 執行結果有錯誤時,則該指令串結束;
若 foo1 執行結果沒有錯誤時,則執行 foo2 | foo3 > foo4 ;
foo2 將 stdout 輸出的結果傳給 foo3 處理;
foo3 將來自 foo2 的 stdout 當成 stdin ,處理完後將資料流重新導向 foo4 這個裝置/檔案
如何秀出在 /bin 底下任何以 a 為開頭的檔案檔名的詳細資料?
ls -l /bin/a*
如何秀出 /bin 底下,檔名為四個字元的檔案?
ls -l /bin/????
如何秀出 /bin 底下,檔名開頭不是 a-d 的檔案?
ls -l /bin/[!a-d]*
當我離開 bash 後,希望系統可以幫我將最近工作的:1.)工作日期; 2.)100 個歷史命令獨立 記錄到 ~/.bash_localcom 檔案中,該如何設定?
我可以編輯 ~/.bash_logout ,將這個檔案內容變成:
# ~/.bash_logout
date >> ~/.bash_localcom
history 100 >> ~/.bash_localcom
clear
我想要讓終端機介面的登入提示字元修改成我自己喜好的模樣,應該要改哪裡?(filename)
/etc/issue
承上題,如果我是想要讓使用者登入後,才顯示歡迎訊息,又應該要改哪裡?
/etc/motd
阅读(1235) | 评论(0) | 转发(0) |
0

上一篇:Bash学习(六)

下一篇:用linux构建路由器

给主人留下些什么吧!~~