天天看點

Linux系統開發: 學習linux三劍客(awk、sed、grep)(上)

一、前言

Linux中的三個指令awk、sed、grep在業界被稱為“三劍客”,grep擅長查找,sed擅長取行和替換,awk擅長運算。

我們知道Linux下一切皆檔案,對Linux的操作就是對檔案的處理,那麼怎麼能更好的處理檔案呢?這就要用到三劍客指令。

三劍客與正規表達式息息相關,正規表達式是為了處理大量的文本|字元串而定義的一套規則和模版,這個模版是由一些普通字元和一些元字元組成。普通字元包括大小寫的字母和數字,而元字元則具有特殊的含義。正規表達式詳情可參看資料《linux正規表達式》。

三劍客與正規表達式是什麼關系呢?

三劍客就是普通的指令,有的把他們叫做工具。而正規表達式就好比一個模版,而linux下一般隻有三劍客能讀懂這個模版。

Linux系統開發: 學習linux三劍客(awk、sed、grep)(上)

二、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)(下)

繼續閱讀