一、前言
Linux中的三個指令awk、sed、grep在業界被稱為“三劍客”,grep擅長查找,sed擅長取行和替換,awk擅長運算。
我們知道Linux下一切皆檔案,對Linux的操作就是對檔案的處理,那麼怎麼能更好的處理檔案呢?這就要用到三劍客指令。
三劍客與正規表達式息息相關,正規表達式是為了處理大量的文本|字元串而定義的一套規則和模版,這個模版是由一些普通字元和一些元字元組成。普通字元包括大小寫的字母和數字,而元字元則具有特殊的含義。正規表達式詳情可參看資料《linux正規表達式》。
三劍客與正規表達式是什麼關系呢?
三劍客就是普通的指令,有的把他們叫做工具。而正規表達式就好比一個模版,而linux下一般隻有三劍客能讀懂這個模版。

二、grep指令
2.1 grep指令功能
grep(global search regular expression(RE) and print out the line,全面搜尋正規表達式并把行列印出來)是一種強大的文本搜尋工具,它能使用正規表達式搜尋文本,并把比對的行列印出來。
Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的指令隻跟grep有很小不同。egrep是grep的擴充,支援更多的re元字元, fgrep就是fixed grep或fast grep,它們把所有的字母都看作單詞,也就是說,正規表達式中的元字元表示回其自身的字面意義,不再特殊。linux使用GNU版本的grep。它功能更強,可以通過-G、-E、-F指令行選項來使用egrep和fgrep的功能。
查找内容可以用雙引号括起來,也可以不用,建議使用雙引号,雙引号中一些特殊符号要注意使用轉義字元。
格式:grep [OPTIONS] PATTERN [FILE...]
grep預設不支援擴充正則,是以擴充正規表達式的符号對于grep來說就等同于普通字元含義,是以,想讓grep直接處理正則符号必須通過轉義字元\{\}來處理。
grep -E 強制讓grep直接認識正則符号,不需要再進行轉義,egrep 等效grep -E 天生就能認識正則符号;我們平時備份可以通過cp 檔案名{,.bak}的形式進行,避免再打一次檔案名
2.2 支援的選項參數
-a 不要忽略二進制資料。
-A <顯示行數> 除了顯示符合範本樣式的行之外,并顯示該行之後的指定幾行内容。
-B<顯示行數> 除了顯示符合範本樣式的行之外,并顯示該行之前的指定幾行内容。
-C<顯示行數> 除了顯示符合範本樣式的那一行之外,并顯示該行前後指定幾行的内容。
-b 在顯示符合範本樣式的那一行之外,并顯示位元組偏移量。-c 隻計算顯示符合範本樣式的行數,不顯示詳細内容
-d<進行動作> 當指定要查找的是目錄而非檔案時,必須使用這項參數,否則grep指令将回報資訊并停止動作。
-e<範本樣式> 指定字元串作為查找檔案内容的範本樣式。
-E 将範本樣式為延伸的普通表示法來使用,意味着能使用擴充正規表達式。
-f <範本檔案> 指定範本檔案,其内容有一個或多個範本樣式,讓grep查找符合範本條件的檔案内容,格式為每一列的範本樣式。
-F 将範本樣式視為固定字元串的清單。
-G 将範本樣式視為普通的表示法來使用。
-h 在顯示符合範本樣式的那一列之前,不标示該列所屬的檔案名稱。
-H 在顯示符合範本樣式的那一列之前,标示該列的檔案名稱。
-i 忽略字元大小寫的差别。
-l 列出檔案内容符合指定的範本樣式的檔案名稱。
-L 列出檔案内容不符合指定的範本樣式的檔案名稱。
-n 在顯示符合範本樣式的那一列,标示出該列的編号。
-q 不顯示任何資訊。
-R/-r 此參數的效果和指定“-d recurse”參數相同,表明查找路徑為目錄
-s 不顯示錯誤資訊。
-v 反轉查找,顯示不符合模式的所有資訊
-w 隻顯示全字元合的列。
-x 隻顯示全列符合的列。
-y 此參數效果跟“-i”相同。
-o 隻輸出檔案中比對到的部分。
--color=auto 把比對部分标記出來,要想目前終端後續使用都要标記比對部分,可用alias指令重新封裝grep。
#alias grep=’grep --color=auto’
2.3 常用示例
在檔案中查找内容
成功會輸出所有包含查找内容的行,否則輸出為空。
$ grep bash file_read.sh #在file_read.sh内查找bash
$ grep "bash" file_read.sh --color=auto #兩者效果相同,并且标記顔色
$ grep "bash" file_read.sh demo.sh #在file_read.sh demo.sh 内查找bash
在目錄下查找内容
成功會輸出檔案名:所有包含内容的行,否則輸出為空
需運用-r/-R/-d recurse 選項參數,指明查找路徑為目錄
$ grep "bash" -r ./ #在目前目錄下查找檔案内容bash
$ grep "bash" -R ./
$ grep "bash" -d recurse ./
顯示查找内容所在行的行号
需運用-n參數,顯示行号,可單獨也可與其他選項參數寫在一起。
$ grep "bash" -n file_read.sh #在file_read.sh内查找bash
$ grep "bash" -Rn ./
$ grep "bash" -r -n ./
反轉顯示,顯示與查找内容不符合的所有内容
需運用-v參數。
$ grep "bash" -vn demo.sh #顯示demo.sh内不包含bash的行,并顯示行号
查找以某内容開頭的行
需運用正規表達式^...。
$ grep "^#" demo.sh #查找demo.sh内以#開頭的行,注意前面不能有空白字元,必須是最開頭
查找空白行
需運用正規表達式...$。
$ grep "^$" 123.txt
查找非指定字元開頭的行
$ grep "^[^#]" demo.sh #在demo.sh中查找不以#開頭的行
查找以某内容結尾的行
$ grep "name$" demo.sh #查找demo.sh内以name結尾的行,注意必須是最後且後面不能有空白字元
需運用-c參數,不顯示詳細内容,隻顯示行數
$ grep "name" demo.sh -c # 在demo.sh中查找name出現的行數
顯示查找内容及其前後行内容
需運用 -A 行數/-B 行數/-C 行數 參數
$ grep "name" demo.sh -A 2 #顯示查找内容及其後兩行内容
$ grep "name" demo.sh -B 2 #顯示查找内容及其前兩行内容
$ grep "name" demo.sh -C 2 #顯示查找内容及其前後兩行内容
查找阿拉伯數字
需要用到正規表達式[m]與{n},選項參數-E(指定使用正規表達式)
[]正規表達式:[m]表明查找比對m字元的内容。
[^m]表明比對不是m字元的内容。
[m-f]表示比對m到f的内容,m可以是數字,可以是字元。
{}正規表達式:{m}表示比對之前的項m次
{m,}表示比對之前的項至少m次
{m,f}表示比對之前的項m次到f次。m是可以為0的正整數。
$ grep "[1-3]\{2\}" 123.txt #在123.txt中查找1-3之間數字出現兩次的内容,注意{}前後一定要加轉義字元
$ grep -E "[1-3]{2}" 123.txt #或者直接使用-E參數指定使用正規表達式,則可不加轉義
$ grep "[1-3][1-3]" 123.txt #與上面相同效果,也表示在123.txt中查找1-3之間數字出現兩次的内容
$ifconfig | grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"
grep用于正常的查詢操作固然友善,但是最大的弊端就是查出來不能增删改,導緻如果是寫一些腳本就會很不友善,這個時候就需要sed和awk這樣的工具來實作。
三、sed指令
3.1 sed指令介紹
sed是一種流編輯器,它是文本進行中非常中的工具,能夠完美的配合正規表達式使用,功能不同凡響。處理時,把目前處理的行存儲在臨時緩沖區中,稱為“模式空間”(pattern space),接着用sed指令處理緩沖區中的内容,處理完成後,把緩沖區的内容送往螢幕。接着處理下一行,這樣不斷重複,直到檔案末尾。檔案内容并沒有改變,除非你使用重定向存儲輸出。Sed主要用來自動編輯一個或多個檔案;簡化對檔案的反複操作;編寫轉換程式等。
指令格式:
sed [options] 'command' file(s)
sed [options] -f scriptfile file(s)
注意:查找的内容前後一定要用/包含起來,示例/sh/ 。替換的時候可用@與#替換/。
指令與查找内容可連在一起也可分開,但是中間必須有/作為間隔。
3.2 sed的工作流程
1、sed預設不編輯原檔案,而是逐行操作,複制一份到指定記憶體(pattern space,模式空間)
2、pattern space内進行模式比對,即和指定條件做比對
不滿足模式:輸出到标準輸出STDOUT
滿足模式:進行指定的模式操作,再輸出到STDOUT
3、第二個特殊的記憶體空間 :保持空間(hold space),臨時儲存操作在另一處記憶體
4、當執行pattern space和 hold space相關選項時候會進行之間的資料流編輯操作
5、最後根據操作執行hold space空間操作,選擇性顯示到STDOUT
3.3 選項參數
-c/--copy 用拷貝代替重命名
-e<script>/--expression=<script> 以選項中的指定的腳本來處理輸入的文本檔案;
-f<script檔案>/--file=<script檔案> 以選項中指定的腳本檔案來處理輸入的文本檔案;
--follow-symlinks 處理輸入的文本檔案時,追蹤軟連結,斷開硬連結
-h/--help 顯示幫助;
-i[SUFFIX]/ --in-place[=SUFFIX] 就地編輯檔案,提供了字尾名(.bak)則備份檔案
-l N/ --line-length=N 為l指令指定換行的長度n
-n/--quiet/——silent 不自動列印模式空間内容,僅顯示腳本處理後的結果,sed預設列印全部内容
--posix 禁用所有GNU擴充
-u/ --unbuffered 從輸入檔案中加載最小的資料并頻繁重新整理輸出緩沖區
-V/--version 顯示版本資訊。
-r/--regexp-extended 支援使用擴充正規表達式
-s/--separate 把檔案作為單獨的個體而不是作為單個連續的長流
3.4 指令參數的使用
指令建議用單引号’’或雙引号括起來友善區分,多個指令用;隔開。
a\ 在目前行下面插入文本。
i\ 在目前行上面插入文本。
c\ 把標明的行改為新的文本。
d 删除,删除選擇的行。
D 删除模闆塊的第一行。
s 替換指定字元,字元間可用/或@或#隔開
h 拷貝模闆塊的内容到記憶體中的緩沖區。
H 追加模闆塊的内容到記憶體中的緩沖區。
g 獲得記憶體緩沖區的内容,并替代目前模闆塊中的文本。
G 獲得記憶體緩沖區的内容,并追加到目前模闆塊文本的後面。
l 清單不能列印字元的清單。
n 讀取下一個輸入行,用下一個指令處理新的行而不是用第一個指令。
N 追加下一個輸入行到模闆塊後面并在二者間嵌入一個新行,改變目前行号碼。
p 列印模闆塊的行。前面可加數字,指定列印第幾行
P(大寫) 列印模闆塊的第一行。
q 退出Sed。
b lable 分支到腳本中帶有标記的地方,如果分支不存在則分支到腳本的末尾。
r file 從file中讀行。
t label if分支,從最後一行開始,條件一旦滿足或者T,t指令,将導緻分支到帶有标号的指令處,或者到腳本的末尾。
T label 錯誤分支,從最後一行開始,一旦發生錯誤或者T,t指令,将導緻分支到帶有标号的指令處,或者到腳本的末尾。
w file 寫并追加模闆塊到file末尾。
W file 寫并追加模闆塊的第一行到file末尾。
! 表示後面的指令對所有沒有被標明的行發生作用。 示例:1!表明對文中所有行起作用,3!表示對文中第三行及以下行起作用
= 列印目前行号碼。
# 把注釋擴充到下一個換行符以前。
3.5 替換标記
g 表示行内全面替換。
p 表示列印行。
w 表示把行寫入一個檔案。
x 表示互換模闆塊中的文本和緩沖區中的文本。
y 表示把一個字元翻譯為另外的字元(但是不用于正規表達式)
\1 子串比對标記
& 已比對字元串标記
3.6 元字元集
^ 比對行開始,如:/^sed/比對所有以sed開頭的行。
$ 比對行結束,如:/sed$/比對所有以sed結尾的行。
. 比對一個非換行符的任意字元,如:/s.d/比對s後接一個任意字元,最後是d。
* 比對0個或多個字元,如:/*sed/比對所有模闆是一個或多個空格後緊跟sed的行。
[] 比對一個指定範圍内的字元,如/[sS]ed/比對sed和Sed。
[^] 比對一個不在指定範圍内的字元,如:/[^A-RT-Z]ed/比對不包含A-R和T-Z的一個字母開頭,緊跟ed的行。
.... 比對子串,儲存比對的字元,如s/loveloveable/\1rs,loveable被替換成lovers。
& 儲存搜尋字元用來替換其他字元,如s/love/**&**/,love這成**love**。
\< 比對單詞的開始,如:/\<love/比對包含以love開頭的單詞的行。
\> 比對單詞的結束,如/love\>/比對包含以love結尾的單詞的行。
x\{m\} 重複字元x,m次,如:/0\{5\}/比對包含5個0的行。
x\{m,\} 重複字元x,至少m次,如:/0\{5,\}/比對至少有5個0的行。
x\{m,n\} 重複字元x,至少m次,不多于n次,如:/0\{5,10\}/比對5~10個0的行。
3.7 腳本位址定界
/ 在sed中作為定界符使用,也可以使用任意的定界符:| /
定界符出現在樣式内部時,需要進行轉義,示例:sed 's/\/bin/\/usr\/local\/bin/g'
不給位址:對全文進行處理
$:表示最後一行
位址範圍:
標明行的範圍:,(逗号)
/pattern/:被此處模式所能夠比對到的每一行
/pattern/,m:被模式比對到的第一行起到m行
n,m 表示從n行到第m行
n,+m 表示從n行起往後增加m行
n~m:步進:以n行為基準值,每次增加m行
3.8 組合多個表達式
sed '表達式' | sed '表達式'
等價于:
sed '表達式; 表達式'
3.9 常用示例
顯示輸入檔案的行号
需用到指令:=:列印目前行号碼(包括空白行)
需用到元字元集:. :比對一個非換行符的任意字元
需用到指令:!: 表示後面的指令對所有沒有被標明的行發生作用。
$ sed '=' 123.txt #顯示文本的每一行行号
$ sed '3=' 123.txt #顯示文本的第三行行号
$ sed "/./=" 123.txt #隻顯示非空白行的行号
$ sed -n "/./!=" 123.txt #隻顯示空白行行号
顯示檔案總行數
需用到元字元集:$:比對到行結束
$ sed '$=' 123.txt #可顯示123.txt内總共有多少行,也就是最後一行的行号
列印輸入檔案的指定行内容
需用到-n參數:不自動列印,
需用到p指令:列印子產品的行
$ sed -n '2p' 123.txt #注意一定要加-n,否則會預設自動列印所有内容
$ sed -n '2 p' 123.txt #注意一定要加-n,否則會預設自動列印所有内容
列印輸入檔案的指定幾行内容
$sed -n '2,7 p' 123.txt #注意一定要加-n,否則會預設自動列印所有内容
$ sed -n '2,7p' 123.txt
$ sed -n '2,7 {p}' 123.txt #指令也可單獨用{}括起來
替換輸入檔案中内容
需用到-i參數:就地編輯檔案,會對源檔案作更改
需用到s指令:替換指定字元,注意字元之間可用/@#隔開,注意如果沒有其他指令或者替換标記作為結尾,最後也必須得由它們作為尾字元,
需用到g替換标記:替換行内的所有比對内容,前面可加數字,表明第幾個比對位置
$ sed -i 's/bck/sh/' 123.txt 666.txt #替換123.txt、666.txt内的bck為sh,每行隻替換一個
$ sed -i 's/bck/sh/g' 123.txt #替換123.txt内的bck為sh,每行都進行全面替換
$ sed -i 's/bck/sh/3g' 123.txt #替換123.txt内的bck為sh,從第3個比對位置開始替換
$ sed -i 's@bck@sh@g' 123.txt #替換123.txt内的bck為sh,每行都進行全面替換
$ sed -i 's#bck#sh#g' 123.txt #替換123.txt内的bck為sh,每行都進行全面替換
替換輸入檔案中指定行的内容
$ sed -i '1,5 s/bck/sh/g' 123.txt 666.txt #替換123.txt、666.txt内的第一行到第五行的bck為sh,每行全面替換
$ sed -i '2,+2 {s/bck/sh/g}' 123.txt 666.txt #替換123.txt、666.txt内的第二行往後兩行的bck為sh,每行全面替換,指令也可以單獨用{}括起來,表示邊界
$ sed -i '2~2 s/bck/sh/g' 123.txt 666.txt #替換123.txt、666.txt内的第二行往後每次增加兩行的bck為sh,每行全面替換
給檔案名\單詞前統一替換加字首或字尾或前字尾
需用到元字元集:^ 比對行開始,如:/^sed/比對所有以sed開頭的行。
需用到元字元集:$ 比對行結束,如:/sed$/比對所有以sed結尾的行。
需用到替換标記:& 已比對字元串标記,代替之前已比對内容
需用到正規表達式:\w\+:比對每一個單詞
$ ls | sed 's/^/666_&/g' #表示給目前檔案下的檔案名統一添加字首
$ ls | sed 's/$/666_&/g' #表示給目前檔案下的檔案名統一添加字尾
$ ls | sed 's/\w\+/666_&/g' #表明給所有的單詞添加字首
$ ls | sed 's/\w\+/[&]/' #表明給每個比對到的單詞用[]括起來
顯示指定區間以指定内容開頭或結尾的行
需用到元字元集^:比對行開始
如果/前面有位址定界,則在/外面必須加上{}
$ sed -n '1,10 {/^10/p}' 123.txt #顯示123.txt内第1到第10行中以10開頭的行
$ sed -n '/^10/p' 123.txt # /前沒有位址定界則可以不加{},如果有則必須加上
$ sed -n '1,10 {/sh$/p}' 123.txt #顯示123.txt内第1到第10行中以結尾的行
顯示查找内容的所有行、顯示找到的第一行及以下指定行
需用到腳本位址定界:/pattern/:被此處模式所能夠比對到的每一行
需用到腳本位址定界:/pattern/,m:被模式比對到的第一行起到m行
需用到腳本位址定界:$ 比對到末尾行
$ sed -n '/sh/p' 123.txt #顯示123.txt内的所有包含sh的所有行
$ sed -n '/sh/ ,$ p' 123.txt #顯示123.txt裡第一條包含sh的行及以下到末尾的所有行
$ sed -n '/sh/ ,$p' 123.txt
逆序輸出文本内容
需用到指令:!:!前跟非零數字,表示後面的指令對所有沒有被標明的行發生作用
需用到指令:G:獲得記憶體緩沖區的内容,并追加到目前模闆塊文本的後面
需用到指令:h: 拷貝模闆塊的内容到記憶體中的緩沖區
需用到指令:d :删除,删除選擇的行。
多個指令之前用分号;隔開。
$ sed '1!G;h;$!d' 123.txt
逆序輸出每行内容
$ sed '/\n/!G;s/..∗\n/&\2\1/;//D;s/.//' 123.txt
删除指定行
需用到指令:d 删除,删除選擇的行。
$ grep -n "sh" 123.txt | sed '4,5d' #删除grep查找到的内容的第4到5行
$ grep -n "sh" 123.txt | sed '1,2d' #删除grep查找到的内容的第1行後每次隔兩行删一行
$ sed '/^$/d' 123.txt #删除空白行
在指定行前後插入内容
需用到指令:a\ 在目前行下面插入文本。預設目前行為最末行
需用到指令:i\ 在目前行上面插入文本。預設目前行為最末行
需用到指令:c\ 把標明的行改為新的文本。預設目前行為所有行
$ sed 'a\hello\' 123.txt #在123.txt的末行後增加一行hello
$ sed 'i\hello\' 123.txt #在123.txt的末行前增加一行hello
$ sed 'c\hello\' 123.txt #替換123.txt的所有行為hello
$ sed '8a\hello\' 123.txt #在123.txt的第8行後增加一行hello
$ sed '8,10a\hello\' 123.txt #在123.txt的第8行到10行每一行後增加一行hello
$ sed '8,10c\hello\' 123.txt #在123.txt的第8行到10行替換為一行hello
一行内執行多條指令
需用到選項參數-e<script>/--expression=<script> 以選項中的指定的腳本來處理輸入的文本檔案;
$ sed -e '1,5d' -e 's/sh/bck/' 123.txt #先删除1到5行再替換sh為bck
$ sed '1,5d;s/sh/bck/' 123.txt #三者效果相同
$ sed --expression='1,5d' --expression='s/sh/bck/' 123.txt #三者效果相同
四、awk指令
續集: Linux入門開發: 學習linux三劍客(awk、sed、grep)(下)