shell編程基礎(七): 處理文件命令sed與awk

1、sed(以行爲單位處理文件)

  sed意爲流編輯器(Stream Editor),在Shell腳本和Makefile中做爲過濾器使用很是廣泛,也就是把前一個程序的輸出引入sed的輸入,通過一系列編輯命令轉換爲另外一種格式輸出。sed和vi都源於早期UNIX的ed工具,因此不少sed命令和vi的末行命令是相同的。html

0、sed命令格式

sed命令行的基本格式爲:正則表達式

sed option 'script' file1 file2 ... sed option -f scriptfile file1 file2 ...

選項含義:centos

--version   顯示sed版本。 --help   顯示幫助文檔。 -n,--quiet,--silent   靜默輸出,默認狀況下,sed程序在全部的腳本指令執行完畢後,將自動打印模式空間中的內容,這些選項能夠屏蔽自動打印。 -e script   容許多個腳本指令被執行。 -f script-file, --file=script-file   從文件中讀取腳本指令,對編寫自動腳本程序來講很棒! -i,--in-place   直接修改源文件,通過腳本指令處理後的內容將被輸出至源文件(源文件被修改)慎用! -l N, --line-length=N   該選項指定l指令能夠輸出的行長度,l指令用於輸出非打印字符。 --posix    禁用GNU sed擴展功能。 -r, --regexp-extended  在腳本指令中使用擴展正則表達式 -s, --separate    默認狀況下,sed將把命令行指定的多個文件名做爲一個長的連續的輸入流。而GNU sed則容許把他們看成單獨的文件,這樣如正則表達式則不進行跨文件匹配。 -u, --unbuffered       最低限度的緩存輸入與輸出。

以上僅是sed程序自己的選項功能說明,至於具體的腳本指令(即對文件內容作的操做)後面咱們會詳細描述,這裏就簡單介紹幾個腳本指令操做做爲sed程序的例子。緩存

a,append 追加 i,insert  插入 d,delete 刪除 s,substitution 替換

如:在輸出testfile內容的第二行後添加"mmzs":app

[root@VM_0_5_centos test]# cat testfile mmzs mmzsblog mmzsit [root@VM_0_5_centos test]# sed "2a mmzs" ./testfile mmzs mmzsblog mmzs mmzsit //刪除2-5行後,輸出刪除後的結果
[root@VM_0_5_centos test]# sed "2,5d" testfile mmzs

sed處理的文件既能夠由標準輸入重定向獲得,也能夠當命令行參數傳入,命令行參數能夠一次傳入多個文件,sed會依次處理。編輯器

sed的編輯命令能夠直接當命令行參數傳入,也能夠寫成一個腳本文件而後用-f參數指定,編輯命令的格式爲:函數

/pattern/action 注:其中pattern是正則表達式,action是編輯操做

sed程序一行一行讀出待處理文件,若是某一行與pattern匹配,則執行相應的action,若是一條命令沒有pattern而只有action,這個action將做用於待處理文件的每一行。工具

一、經常使用的sed命令

/pattern/p 打印匹配pattern的行
/pattern/d 刪除匹配pattern的行
/pattern/s/pattern1/pattern2/ 查找符合pattern的行,將該行第一個匹配pattern1的字符串替換爲pattern2
/pattern/s/pattern1/pattern2/g 查找符合pattern的行,將該行全部匹配pattern1的字符串替換爲pattern2

使用p命令須要注意,sed是把待處理文件的內容連同處理結果一塊兒輸出到標準輸出的,所以p命令表示除了把文件內容打印出來以外還額外打印一遍匹配pattern的行。例如:ui

一個文件testfile的內容是:
[root@VM_0_5_centos test]# cat testfile mmzs mmzsblog mmzsit abc 123
打印其中包含abc的行
[root@VM_0_5_centos test]# sed '/abc/p' testfile mmzs mmzsblog mmzsit abc abc 123
要想只輸出處理結果,應加上-n選項,這種用法至關於grep命令
[root@VM_0_5_centos test]# sed -n '/abc/p' testfile abc 使用d命令就不須要-n參數了,好比刪除含有abc的行
[root@VM_0_5_centos test]# sed '/abc/d' testfile mmzs mmzsblog mmzsit 123

注意:sed命令不會修改原文件,刪除命令只表示某些行不打印輸出,而不是從原文件中刪去。spa

使用查找替換命令時,能夠把匹配pattern1的字符串複製到pattern2中,例如:

[root@VM_0_5_centos test]# sed 's/bc/-&-/' testfile mmzs mmzsblog mmzsit a-bc-
123
pattern2中的&表示原文件的當前行中與pattern1相匹配的字符串 再好比:
[root@VM_0_5_centos test]# sed 's/\([a-z]\)\([a-z]\)/-\1-~\2~/' testfile -m-~m~zs -m-~m~zsblog -m-~m~zsit -a-~b~c 123
pattern2中的\1表示與pattern1的第一個()括號相匹配的內容,\2表示與pattern1的第二個()括號相匹配的內容。

注意:sed默認使用Basic正則表達式規範,若是指定了-r選項則使用Extended規範,那麼()括號就沒必要轉義了。

[root@VM_0_5_centos test]#  sed  's/yes/no/;s/mm/MM/'  ./testfile 注:使用分號隔開指令。
 [root@VM_0_5_centos test]# sed -e 's/yes/no/' -e 's/mm/MM/' testfile 注:使用-e選項。

二、練習:

若是testfile的內容是:

<html><head><title>Hello World</title></head>
<body>Welcome to the world of mmzs!</body></html>

如今要去掉全部的HTML標籤,使輸出結果爲:

Hello World
Welcome to the world of mmzs!

怎麼作呢?若是用下面的命令:

[root@VM_0_5_centos test]# sed 's/<.*>//g' testfile

結果是兩個空行,把全部字符都過濾掉了。這是由於,正則表達式中的數量限定符會匹配儘量長的字符串,這稱爲貪心的(Greedy)。好比sed在處理第一行時,<.*>匹配的並非或這樣的標籤,而是:

<html><head><title>Hello World</title>

這樣一整行,由於這一行開頭是<,中間是若干個任意字符,末尾是>。那麼這條命令怎麼改纔對呢?答案以下:

錯誤:獲得兩個空行,匹配過多
[root@VM_0_5_centos test]# sed 's/<.*>//g' testfile 限定了匹配的行
[root@VM_0_5_centos test]# sed '/Hello World/s/<[/ a-z]*>//g' testfile Hello World <body>Welcome to the world of mmzs!</body></html>
不完美示例,由於{4,5}致使可擴展性差
[root@VM_0_5_centos test]# sed -r 's/<(\/)?[a-z]{4,5}>//g' testfile Hello World Welcome to the world of mmzs!
正確示例0:
[root@VM_0_5_centos test]# sed 's/<[/ a-z]*>//g' testfile Hello World Welcome to the world of mmzs!
正確示例1:
[root@VM_0_5_centos test]# sed 's/<[^>]*>//g' testfile Hello World Welcome to the world of mmzs!

注:上面代碼中的紅色部分表示pattern1部分的匹配規則,此處的/也不表示轉義,是語法中的(有點相似分隔符的意思)

2、awk(以列爲單位處理文件)

  sed以行爲單位處理文件,awk比sed強的地方在於不只能以行爲單位還能以列爲單位處理文件。awk缺省的行分隔符是換行,缺省的列分隔符是連續的空格和Tab,可是行分隔符和列分隔符均可以自定義,好比/etc/passwd文件的每一行有若干個字段,字段之間以:分隔,就能夠從新定義awk的列分隔符爲:並以列爲單位處理這個文件。awk其實是一門很複雜的腳本語言,還有像C語言同樣的分支和循環結構,可是基本用法和sed相似。

0、awk命令格式

awk命令行的基本形式爲:

awk option 'script' file1 file2 ... awk option -f scriptfile file1 file2 ...

和sed同樣,awk處理的文件既能夠由標準輸入重定向獲得,也能夠當命令行參數傳入,編輯命令能夠直接當命令行參數傳入,也能夠用-f參數指定一個腳本文件,編輯命令的格式爲:

/pattern/{actions} condition{actions} 和sed相似,pattern是正則表達式,actions是一系列操做

解釋:awk程序一行一行讀出待處理文件,若是某一行與pattern匹配,或者知足condition條件,則執行相應的actions,若是一條awk命令只有actions部分,則actions做用於待處理文件的每一行。

一、經常使用命令

好比文件testfile的內容表示某商店(產品-價格-銷量):

[root@VM_0_5_centos test]# cat testfile ProductA 30 13 ProductB 76 46 ProductC 55 32

打印每一行的第二列:

[root@VM_0_5_centos test]# awk '{print $2;}' testfile 30
76
55

自動變量$一、$2分別表示第一列、第二列等,相似於Shell腳本的位置參數,而$0表示整個當前行。再好比,若是某種產品的庫存量低於75則在行末標註須要定貨:

[root@VM_0_5_centos test]# awk '$2<75 {printf "%s\t%s\n", $0, "REORDER";} $2>=75 {print $0;}' testfile ProductA 30 13 REORDER ProductB 76 46 ProductC 55 32    REORDER

可見awk也有和C語言很是類似的printf函數。awk命令的condition部分還能夠是兩個特殊的condition-BEGIN和END,對於每一個待處理文件,BEGIN後面的actions在處理整個文件以前執行一次,END後面的actions在整個文件處理完以後執行一次。

awk命令能夠像C語言同樣使用變量(但不須要定義變量),好比統計一個文件中的空行數:

[root@VM_0_5_centos test]# cat testfile ProductA 30 13 ProductB 76 46 ProductC 55 32 [root@VM_0_5_centos test]# awk '/^ *$/ {x=x+1;} END {print x;}' testfile 2

就像Shell的環境變量同樣,有些awk變量是預約義的有特殊含義的:

awk經常使用的內建變量:

FILENAME 當前輸入文件的文件名,該變量是隻讀的 NR     當前行的行號,該變量是隻讀的,R表明record NF     當前行所擁有的列數,該變量是隻讀的,F表明field OFS     輸出格式的列分隔符,缺省是空格 FS     輸入文件的列分融符,缺省是連續的空格和Tab ORS     輸出格式的行分隔符,缺省是換行符 RS     輸入文件的行分隔符,缺省是換行符

例如打印系統中的用戶賬號列表:

[root@VM_0_5_centos test]# awk 'BEGIN {FS=":"} {print $1;}' /etc/passwd root bin daemon
相關文章
相關標籤/搜索