1. 程式人生 > >三劍客基礎詳解(grep、sed、awk)

三劍客基礎詳解(grep、sed、awk)

字符操作 解釋 一行 nan 怎麽 you 初見 至少 才會

三劍客基礎詳解

三劍客之grep詳解

通配符與正則表達式這兩口子可以說貫穿三劍客始終,甚至時貫穿linux始終,這樣說,我覺得並不誇張。因此在寫三劍客之前,先捋一捋這些這些知識點就很有必要了。

相對而言正則用於三劍客多一些,通配符用於Linux命令行多一些。

1.通配符

通配符 描述
* 任意多個字符
任意單個字符
. 當前目錄
.. 上級目錄
命令分隔符
~ 當前用戶家目錄
$ 引用變量
! 邏輯運算非
&& 前一個命令執行成功,則執行後面的命令
|| 當前命令執行失敗,則執行後面命令
單引號,原樣輸出,所見即所得
" 雙引號,可以置換變量的值,不加引號相當於雙引號
` 反引號中的內容會被優先解析
- 之前所在路徑
{} shell腳本命令組合;命令行中內容序列
> 重定向覆蓋
>> 重定向追加

2.基礎正則

  • ^錨定行首,如^word表示以word開頭的行
  • $錨定行首,如word$表示以word結尾的行
  • ^$則表示空行
  • . 任意單個字符
  • *匹配其前面字符任意多次
  • .*表示匹配所有字符
  • 轉義字符,使得特殊字符失去特殊含義
  • []匹配範圍內的單個字符
  • [^]匹配範圍外的單個字符
  • 指定匹配次數的範圍,即分組
    1. \{n,m\} 匹配前面字符n到m次
    2. \{n,\} 匹配前面字符至少n次
    3. \{,m\}匹配前面字符至多m次
    4. \{n\} 匹配前面字符n次

      在擴展正則中可以去掉轉義符,即egrep 或者 grep -E

3.grep 講解

3.1語法格式

grep [OPTIONS] [PATTERN] [FILE..]

grep [選項] [過濾的內容] [源文件]

3.2常用參數

  • -n 顯示過濾內容所在行數
  • -o 只顯示匹配到的內容,不會按行輸出
  • -i 忽略大小寫
  • -v 反向選擇,顯示未匹配到的內容
  • -E 支持拓展正則
  • -A 匹配到的行後面幾行,即After
  • -B 匹配到的行前面幾行,即Before
  • -C 配到的行前後幾行,即context上下文
#準備好實驗內容
randolf@localhost:~/test $ ls && cat sed2.txt 
inittab  sed2.txt  test.md5  test.txt
Oh/my/god,dear me!
hello word
you are so cute
what do you think of the party
I am so glad to tell you that I am crazy about Linux!
Linux is better than Windows much more.
#顯示以hello開頭的行,並且顯示其所在行數
randolf@localhost:~/test $ grep -n "^hello" sed2.txt 
2:hello word
#顯示以cute結尾的行,並且只打印匹配到的內容
randolf@localhost:~/test $ grep -o "cute$" sed2.txt 
cute
#顯示不包含單詞you的行
randolf@localhost:~/test $ grep -v "you" sed2.txt 
Oh/my/god,dear me!
hello word
Linux is better than Windows much more.

4.拓展正則

  1. + 重復匹配前面字符1次及1次以上(區別於*匹配0次至多次)
  2. ? 重復匹配前面字符0次或者1次(.表示任意一個字符,不是匹配)
  3. | 可以同時過濾多個字符
  4. () 分組過濾,向後引用(也叫方向引用),將組中的內容作為一個整體來匹配,突破了只能匹配前面單個字符的限制,常常結合分組的使用
#新建測試文本test
randolf@localhost:~/test $ cat > test<<EOF
> gods
> gds
> goods
> gooods
> goads
> EOF
#分別演示+ ? . 的用法
randolf@localhost:~/test $ egrep "go?ds" test 
gods
gds
randolf@localhost:~/test $ egrep "go+ds" test 
gods
goods
gooods
randolf@localhost:~/test $ egrep "go.ds" test 
goods
goads
#演示 | 的多字符過濾
randolf@localhost:~/test $ egrep "gds|goods" test 
gds
goods
#向後引用結合分組的演示
randolf@localhost:~/test $ echo "goodsgoods" >> test
randolf@localhost:~/test $ grep -E ‘(goods){2}‘ test 
goodsgoods

5.POSIX字符類

括號類 含義
[:alnum:] 字母數字字符
[:alpha:] 字母字符
[:digit:] 數字字符
[:graph:] 非空白字符(非空格、控制字符等)
[:lower:] 小寫字母
[:print:] 與[:graph:]相似,但是包含空格字符
[:punct:] 標點字符
[:upper:] 大寫字母
[:xdigit:] 允許十六進制的數字
[:cntrl:] 控制字符

字符類用的較少,放在這裏僅作備用

三劍客之sed講解

sed全稱為Stream Editor即流編輯器,用於過濾和轉換文本,常用的功能包括增刪改查,過濾,取行。

1.sed的執行流程

sed作為流編輯器僅支持單行操作,每次啟動sed進程時,linux會為它在內存中單獨分配一個專屬的空間,我們稱其為模式空間。sed每次只讀取文本中的一行到模式空間中,執行完指定的sed內置命令後,默認將模式空間中的文本打印到屏幕上,然後刪除模式空間中的文本,再讀取原文本中的第二行,重復上面的操作,直至文本的最後一行。

技術分享圖片

2.語法格式

sed [option] [AddressCommand] [input-file]

2.1option:

  • -n 靜默模式
  • -i 編輯原文件
  • -r 支持拓展正則

2.2 Address:

這裏的地址我們指sed所篩選的目標行,支持模式匹配,即使用通配符等。

地址表示形式 描述
1 操作第1行
1,3 操作第1到3行
1,+3 操作第1行以及後面3行(1到4行)
1,$ 操作第1行到最後一行
1~2 通用(n~m),從第n行開始,步進為進行m篩選,如1~2表示第1、3、5....行

以上地址表示皆支持模式匹配,如

地址表示形式 描述
/word/ 操作所有匹配到word這個單詞所在行
/word/,/Linux/ 操作匹配到word的行一直到匹配到Linux的行,遵循懶漢模式的搜索匹配
/word/,+3 操作匹配到word的行以及後面三行(從第一次匹配到word開始)
/word/,$ 操作匹配到word的行一直到最後一行(從第一次匹配到word開始)

懶漢模式匹配:第一次搜索到的結果(word)作為開始,並且第一次搜索到的結果作為(Linux)作為結尾

2.3 Command

此處命令指的是sed編輯器的內置命令,而不是linux的系統命令

現在創建如下文件touch /home/randolf/test/sed.txt

並且寫入內容,作為實驗文本:

cat >sed.txt<<EOF
>0.I am the whole word
>1.hello word
>2.you are so cute
>3.what do you think of the party
>4.I am so glad to tell you that I am crazy about Linux!
>5.Linux is better than Windows much more.
>EOF

地址表示形式與命令的搭配太多不可能一一演示,下面選取典型場景,為大家演示

  • p 打印行

    #打印第2到3行
    randolf@localhost:~/test $ sed ‘2,3p‘ sed.txt
    0.I am the whole word
    1.hello word
    1.hello word
    2.you are so cute
    2.you are so cute
    3.what do you think of the party
    4.I am so glad to tell you that I am crazy about Linux!
    5.Linux is better than Windows much more.

    咦?怎麽打印這麽多東西。我明明只選取2到3行呀。還記得上面說的嘛,“執行完指定的sed內置命令後,默認將模式空間中的文本打印到屏幕上”,沒錯,sed除了將我們選取的內容打印一遍,還沒有忘記自己本來的職責,即打印一遍模式空間中的內容。所以就看了以上打印內容,2到3行打印了兩遍。那如果不想要sed默認打印模式空間咋辦?真相只有一個!選項-n,他表示靜默模式,即不再默認打印模式空間中的內容,試試看嘍。

    randolf@localhost:~/test $ sed -n ‘2,3p‘ sed.txt
    1.hello word
    2.you are so cute
    #頓時清爽多了,舒服
    #打印匹配到word的行一直到匹配到Linux的行,遵循懶漢模式的搜索匹配
    randolf@localhost:~/test $ sed -n ‘/word/,/Linux/p‘ sed.txt 
    0.I am the whole word
    1.hello word
    2.you are so cute
    3.what do you think of the party
    4.I am so glad to tell you that I am crazy about Linux!

    對比原來的文本中,含單詞word的行有兩行,同樣含單詞Linux的行也有兩行,而作為起始行與結束行的都時匹配到的第一個結果,即遵循懶漢模式

  • s 替換行

    #將第一行中"the whole word"替換為"a student"
    randolf@localhost:~/test $ sed ‘s/the whole word/a student/‘ sed.txt 
    0.I am a student
    1.hello word
    2.you are so cute
    3.what do you think of the party
    4.I am so glad to tell you that I am crazy about Linux!
    5.Linux is better than Windows much more.
    #這裏替換的只是sed模式空間中的內容,若想要直接操作員文本,可以使用選項-i
    randolf@localhost:~/test $ sed -i ‘s/the whole word/a student/‘ sed.txt
    #當我們直接操作原文本時,同樣也是不打印模式空間的
    randolf@localhost:~/test $ cat sed.txt 
    0.I am a student
    1.hello word
    2.you are so cute
    3.what do you think of the party
    4.I am so glad to tell you that I am crazy about Linux!
    5.Linux is better than Windows much more.

    sed的內置命令s中的邊界符除了“/”,還可以使用“#”、"@"等特殊符號,常用於避免和原文本中的符號產生沖突,雖然也可以使用轉義符避免沖突,不過轉義符可能讓你眼花繚亂。。

    舉個例子

    #使用vim將剛剛的文本第一行修改為"0.Oh/my/god,dear me!",並執行復制cp sed.txt sed2.txt
    #目標:將Oh/my/god修改為honey
    #1.使用"@"作為定界符修改sed.txt
    randolf@localhost:~/test $ sed ‘s@Oh/my/god@honey@‘ sed.txt |head -n 1
    0.honey,dear me!
    #2.使用"/"作為定界符修改sed2.txt
    randolf@localhost:~/test $ sed ‘s/Oh\/my\/god/honey/‘ sed2.txt |head -n 1
    0.honey,dear me!
    #雖然都能實現操作,可這視覺效果實在不堪,讓我這老花眼暈一會。。。
  • d 刪除行

    #讀入模式空間後直接刪除讀入的行,不讓他打印到屏幕上來
    #刪除1到3行
    randolf@localhost:~/test $ sed ‘1,3d‘ sed.txt 
    3.what do you think of the party
    4.I am so glad to tell you that I am crazy about Linux!
    5.Linux is better than Windows much more.
    #操作原文本,刪除第一行
    #先瞄一眼,未刪除之前第一二行是啥
    randolf@localhost:~/test $ sed -n ‘1p‘ sed.txt| head -n 2
    0.Oh/my/god,dear me!
    1.hello word
    #執行刪除命令
    randolf@localhost:~/test $ sed -i ‘1d‘ sed.txt 
    randolf@localhost:~/test $ sed -n ‘1p‘ sed.txt| head -n 1
    1.hello word
    #看到了吧,原文件中第1行成功刪除,原本的第2行上位成第一行
  • a 目標行後面追加一行

    #最後一行後面添加一行內容,"The earth is beautiful"
    randolf@localhost:~/test $ sed -i ‘$a The earth is beautiful‘ sed.txt 
    randolf@localhost:~/test $ sed -n ‘$p‘ sed.txt 
    The earth is beautiful
    #成功!!!
  • i 目標行前面追加一行
#第一行前面添加一行內容,"This is a start line added just now!"
randolf@localhost:~/test $ sed -i ‘1i This is a start line added just now!‘ sed.txt 
randolf@localhost:~/test $ sed -n ‘1p‘ sed.txt 
This is a start line added just now!
#So easy!!!

三劍客之Awk

awk作為三劍客中最最復雜的老大哥,常常被稱為awk語言,那麽,詳細解釋是不可能的,這輩子都不可能的。。。聊點皮毛

1.awk初見面

1.1awk的簡單介紹

1977年由Alfred Aho 、Peter Weinberger 和 Brian Kernighan這三位同學創造,並以其名字的首字母命名該語言。

版本:awk同樣分為不同的版本,如gawk、dawk、pawk,mawk等,在Linux裏常使用的是gawk(紅帽系列)、和mawk(烏班圖系列)。我在使用的是rhel的社區版centos7,所以記錄的也將是gawk的使用。

1.2 awk的工作機制

類似其他兩位劍客(sed、grep),awk也是按行讀取,過濾用戶給定的匹配模式,並且執行特定的處理動作

組成部分(重要):pattern {action}

即匹配的模式(支持正則)和對匹配到的內容所執行的處理動作

兩個特殊的模式:BEGIN END顧名思義,這兩家夥分別表示在讀取模式所匹配的數據之前執行,和在全部讀取完數據之後執行

兩個註意點:1.若未給定模式,則匹配所有 2.若沒有指明處理行為,則默認執行打印動作print

毫不誇張地說,理解awk的組成,也就掌握其一半的使用能力了。

2.常用選項

Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] ‘program‘ file ...
POSIX options:      GNU long options: (standard)
    -f progfile     --file=progfile #從腳本中加載awk的命令
    -F fs           --field-separator=fs #指定分隔符
    -v var=val      --assign=var=val   #處理動作執行前設置一個變量val

-f加載的腳本中放置的是awk結構的命令,包括 pattern {action}

當需要指定多個分隔符時,可以以通過內置變量FS設置

多個動作處理條件以空格隔開,如{action1} {action2} {action3}.....

#案例素材
randolf@zrm:~/test $ cat test 
centos|ubuntu|arch
apple,orange,banana dog cat
#以|為分隔符,打印$3、$NF
randolf@zrm:~/test $ awk -F ‘|‘ ‘{print $NF}‘ test
arch
apple,orange,banana dog cat
randolf@zrm:~/test $ awk -F ‘|‘ ‘{print $3}‘ test
arch

NF為內置變量,表示當前記錄的個數,那麽思考一下,$3的打印結果為什麽第二行為空呢?
我們前面提到awk是按行讀取的,所以對於awk來說每一行就是一個操作範圍,第一行被"|"分為三個字段,因此記錄個數為3,即$NF的值是3,所以第一行的值輸出相同;而第二行沒有分隔符"|",所以整行只有一個字段記錄,因此$NF的值為1,輸出整行,而$3在第二行不存在,所以輸出空白行。
#重新編輯test文本內容
randolf@zrm:~/test $ cat test
centos|ubuntu|arch
apple,orange,banana dog cat

nihaoa,xiongdi

woshiyizhishuaiguo
#編寫簡單腳本供awk調用
randolf@zrm:~/test $ echo "/^$/ {print \"我是一只空行\"}" > haha   #雙引號需要轉義
randolf@zrm:~/test $ cat haha 
/^$/ {print "我是一只空行"}    #註意中間有空格
randolf@zrm:~/test $ awk -f awk.sh test
我是一只空行
我是一只空行
#BEGIN字段應用舉例(2014年兄弟連 沈超李明老師經典教程)
randolf@zrm:~/test $ awk  ‘{FS=":"} {print $1}‘ /etc/passwd |head -4
root:x:0:0:root:/root:/bin/bash
bin
daemon
adm
randolf@zrm:~/test $ awk  ‘BEGIN{FS=":"} {print $1}‘ /etc/passwd |head -4
root
bin
daemon
adm
#內容太長僅以4行為例,看到了麽,未加BEGIN時第一行沒有被分隔,哈哈,是不是蒙圈了?其實很好理解,awk會事先讀取一行文本的內容,然後才會去找前面的條件,此處為設定的分隔符,嗯哼?想一想前面提到過的BEGIN的定義,BEGIN做兩大特殊模式之一,表示在讀取模式所匹配的數據之前執行,所以呢,加上BEGIN後,awk會先讀取BEGIN後的條件。^_^

3.內置變量

變量名稱 描述
ARGC 命令行參數個數
FILENAME 當前輸入文檔的名稱
FNR 當前輸入文檔的記錄編號,多個輸入文檔時有用
NR 輸入流當前記錄編號
NF 當前記錄的字段個數
FS 字段分隔符
OFS 輸出字段分隔符,默認是空格
ORS 輸出記錄分隔符,默認換行符 \n
RS 輸入記錄分隔符,默認換行符

4.表達式與操作符

4.1表達式的組成部分

表達式由變量,常量,函數,正則表達式,操作符組成
awk中變量有字符變量和數字變量,如果在awk中定義變量沒有初始化,則初始化值為空字符或0。字符操作必須加引號,如 a="hello word"

4.2 常見操作符

+ - * / (加減乘除。。)

% 取余 ^ 冪運算 ++ -- += -= *+ /= ‘>‘

<       >=      <=       == 等於   !=     ~匹配     !~不匹配   &&與      ||或
#操作符簡單舉例
randolf@zrm:~/test $ echo test  | awk ‘x=2 {print x+=1}‘
3
randolf@zrm:~/test $ echo hello | awk ‘x=1,y=3 {print x*2,y*3}‘
2 9
#表達式與模式END結合使用
randolf@zrm:~/test $ awk ‘/^$/ {x+=1} END {print x}‘ test
2
#打印root用戶的UID,cat一下知道,/etc/passwd文件中第三個字段是用戶的UID
randolf@zrm:~/test $ awk -F: ‘$1~/root/ {print $3}‘ /etc/passwd
0

三劍客基礎詳解(grep、sed、awk)