Grep Sed Awk

grep、sed和awk都是文本處理工具,雖然都是文本處理工具單卻都有各自的優缺點,一種文本處理命令是不能被另外一個徹底替換的,不然也不會出現三個文本處理命令了。只不過,相比較而言,sed和awk功能更強大而已,且已獨立成一種語言來介紹。mysql

grep:文本過濾器,若是僅僅是過濾文本,可以使用grep,其效率要比其餘的高不少;
sed:Stream EDitor,流編輯器,默認只處理模式空間,不處理原數據,若是你處理的數據是針對行進行處理的,可使用sed;

awk:報告生成器,格式化之後顯示。若是對處理的數據須要生成報告之類的信息,或者你處理的數據是按列進行處理的,最好使用awk。linux

 

grep
grep 是一個最初用於Unix操做系統的命令行工具。在給出文件列表或標準輸入後,grep會對匹配一個或多個正則表達式的文本進行搜索,並只輸出匹配(或者不匹配)的行或文本。Unix的grep家族包括grep、egrep和fgrep
egrep和fgrep的命令只跟grep有很小不一樣。egrep是grep的擴展,支持更多的re元字符fgrep就是fixed grep或fast grep,它們把全部的字母都看做單詞,也就是說,正則表達式中的元字符表示回其自身的字面意義,再也不特殊。linux使用GNU版本的grep。它功能更強,能夠經過-E、-F命令行選項來使用egrep和fgrep的功能。
grep的工做方式是這樣的,它在一個或多個文件中搜索字符串模板。若是模板包括空格,則必須被引用,模板後的全部字符串被看做文件名。搜索的結果被送到屏幕,不影響原文件內容。
grep可用於shell腳本,由於grep經過返回一個狀態值來講明搜索的狀態,若是模板搜索成功,則返回0,若是搜索不成功,則返回1,若是搜索的文件不存在,則返回2。咱們利用這些返回值就可進行一些自動化的文本處理工做。

grep:根據模式搜索文本,並將符合模式的文本行顯示出來。    
Pattern:文本字符和正則表達式的元字符組合而成匹配條件

使用格式:
grep [options] PATTERN [FILE...]
    -i:忽略大小寫    
    --color:匹配到字符用其餘顏色顯示出來,默認是紅色
    -v:顯示沒有被模式匹配到的行
    -o:只顯示被模式匹配到的字符串,不顯示行
    -E:使用擴展正則表達式
    -A n:表示顯示該行及其後n行
    -B n:表示顯示該行及其前n行
    -C n:表示顯示該行及其先後各n行
正則表達式:REGular EXPression,REGEXP
元字符:
.:匹配任意單個字符
[]:匹配指定範圍內的任意單個字符
[^]:匹配指定範圍外的任意單個字符
   字符集和:[:digit:],[:lower:],[:upper:],[:punct:],[:space:],[:alpha:],[:alnum:]
    對應上邊:數字  ,小寫字母,大寫字母,標點符號,空白字符,全部字母,全部數字和字母

匹配次數(貪婪模式,即儘量長的匹配):
*:匹配其前面的字符任意次
   如:編輯文件abc,輸入這些字符:a,b,ab,aab,acb,adb,amnb,使用grep匹配a*b,命令及顯示效果以下所示:
從 上圖能夠看到,雖然像acb、adb之類的字符串也能夠顯示出來,但從顯示的顏色能夠看到,匹配的僅僅是字符b,雖然整個字符串中也有字符a,可是此時a 並無與b一塊兒緊挨着出現,因此僅匹配到字符b;而像ab、aab等字符串,所有顯示,此時a緊挨着b出現,符合條件,因此能夠顯示。

.*:任意長度的任意字符
    如:匹配.b和.*b,看兩者有什麼區別,命令和顯示效果以下:

 

\?:匹配其前面的字符1次或0次nginx

    如:繼續上邊的例子,如今匹配a\?b,顯示效果以下所示:

 

\{m,n\}:匹配其前面的字符至少m次,至多n次git

   \{1,\}:至少一次
   \{0,3\}:最多三次

位置錨定:
^:錨定行首,此字符後面的任意內容必須出如今行首    
$:錨定行尾,此字符前面的任意內容必須出如今行尾
^$:空白行
\<或\b:錨定詞首,其後面的任意字符必須做爲單詞首部出現
\>或\b:錨定詞尾,其後邊的任意字符必須做爲單詞尾部出現

    如:\<root\>:在整個文件中,把root做爲整個單詞出現,詞首詞尾都不行,如:mroot、rooter均將不匹配
舉幾個例子來講明下上邊的位置錨定。

 

分組:web

\(\)
   如: \(ab\)*:ab總體做爲匹配字符,且匹配任意次
          \(ab\)\{1,\}:ab總體做爲匹配字符,且匹配至少一次
          \(ab\):ab總體做爲匹配字符

    後向引用
    \1:匹配第一個左括號以及與之對應的右括號所包括的全部內容
    \2:匹配第二個左括號以及與之對應的右括號所包括的全部內容
    \3:匹配第三個左括號以及與之對應的右括號所包括的全部內容
    ......
    如:
新建文件test1,添加內容以下:
He love his lover.
She like her liker.
He love his liker.
She like her lover.
He like her.
She love he.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vim test1     #編輯該文件添加以下內容:
He love his lover.
She like her liker.
He love his liker.
She like her lover.
He like her.
She love he.
[root@www ~] # grep '\(l..e\).*\1' test1    #匹配前邊第一個左括號的以及與之對應的右括號的內容
He love his lover.
She like her liker.
[root@www ~] # grep 'l..e' test1          #匹配指定的字符,中間可爲任意兩個字符
He love his lover.
She like her liker.
He love his liker.
She like her lover.
He like her.
She love he.

 

grep練習:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
一、顯示 /proc/meminfo 文件中以不區分大小的s開頭的行;
      grep -i '^s' /proc/meminfo    或者
      grep '^[sS]' /proc/meminfo   #[]表示匹配指定範圍內的單個字符,所以也可實現不區分大小寫
二、顯示 /etc/passwd 中以nologin結尾的行;
      grep 'nologin$' /etc/passwd
      擴展一:取出默認shell爲 /sbin/nologin 的用戶列表
            grep '/sbin/nologin' /etc/passwd | cut -d: -f1    或者
            grep '/sbin/nologin' /etc/passwd | awk -F: '{print $1}'     或者直接使用 awk
            awk -F: '$7 ~ /nologin/{print $1}' /etc/passwd
      擴展二:取出默認shell爲 bash ,且其用戶ID號最小的用戶的用戶名
            grep 'bash$' /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1   或者
            awk -F: '$7 ~ /bash/{print $3,$1}' /etc/passwd | sort -n | head -1 | awk '{print $2}'
三、顯示 /etc/inittab 中以 #開頭,且後面跟一個或多個空白字符,然後又跟了任意非空白字符的行;
       grep '^#[[:space:]]\{1,\}[^[:space:]]' /etc/inittab
四、顯示 /etc/inittab 中包含了:一個數字:(即兩個冒號中間一個數字)的行;
       grep ':[0-9]:' /etc/inittab
五、顯示 /boot/grub/grub .conf文件中以一個或多個空白字符開頭的行;
       grep '^[[:space:]]\{1,\}' /boot/grub/grub .conf
六、顯示 /etc/inittab 文件中以一個數字開頭並以一個與開頭數字相同的數字結尾的行;
       grep '\(^[0-9]\).*\1$' /etc/inittab     #在RHEL5.8之前的版本中可查看到效果
七、找出某文件中的,1位數,或2位數;
       grep '\<[[:digit:]][[:digit:]]\?\>' /etc/inittab  或者
       grep '\<[0-9]\{1,2\}\>' /etc/inittab
八、查找當前系統上名字爲student(必須出如今行首)的用戶的賬號的相關信息, 文件爲 /etc/passwd
       grep '^student:' /etc/passwd
       擴展:若存在該用戶,找出該用戶的ID號:
             grep '^student:' /etc/passwd | cut -d: -f3  或者 # id -u student
思考題:用多種方法找出本地的IP地址,這裏給出三種方法,若是你還有其餘方法能夠一塊兒分享下:
1
2
3
ifconfig eth0| grep -oE '([0-9]{1,3}\.?){4}' | head -n 1
ifconfig eth0| awk -F: '/inet addr/{split($2,a," ");print a[1];exit}'     #這裏使用了awk的內置函數,若是不懂可在看完awk的介紹後再來作此題
ifconfig | grep "inet addr" | grep - v "127.0.0.1" | awk -F: '{print $2}' | awk '{print $1}'

 

sed
sed(意爲流編輯器,源自英語stream editor」的縮寫)是Unix常見的命令行程序。sed 用來把文檔或字符串裏面的文字通過一系列編輯命令轉換爲另外一種格式輸出。sed 一般用來匹配一個或多個正則表達式的文本進行處理。sed是一種在線編輯器, 它一次處理一行內容。處理時,把當前處理的行存儲在臨時緩衝區中,稱爲「模式空間」(pattern space),接着用sed命令處理緩衝區中的內容,處理完成後,把緩衝區的內容送往屏幕。接着處理下一行,這樣不斷重複,直到文件末尾。文件內容並無 改變,除非你使用重定向存儲輸出。Sed主要用來自動編輯一個或多個文件;簡化對文件的反覆操做;編寫轉換程序等。

使用格式:    
sed 'AddressCommand' file ...
    -n:靜默模式,再也不顯示模式空間中的內容
    -i:直接修改原文件
    -e SCRIPT -e SCRIPT:添加腳本到將要執行的命令中,能夠同時執行多個腳本
    -f /PATH/TO/SED_SCORIPT:添加腳本文件中的內容到將要執行的命令中
         #sed -f /path/to/script file
    -r:表示使用擴展正則表達式

Address:
一、StartLine,EndLine:開始行,結束行
   如:1,100:表示從第1行到第100行
    $;最後一行
二、/RegExp/:擴展正則表達式
   如:/^root/
三、/pattern1/,/pattern2/:表示第一次被pattern1匹配到的行開始,至第一次被pattern2匹配到的行結束,這中間的全部行
四、LIneNumber:指定的行
五、StartLIne,+N:從StartLine開始,向後的N行

Command:
    d:刪除符合條件的行;
    p:顯示符合條件的行,在不使用-n選項時被匹配到的行會顯示兩遍,由於sed處理時會把處理的信息輸出
    a \string:在指定的行後面追加新行,內容爲「string」,
        顯示兩行或多行,在每行後加\n進行換行
    i \string:在指定的行前面添加新行,內容爲string
    r file:將指定的文件的內容添加至符合條件的文件中
    w file:將地址指定範圍內的行另存至指定的文件中
    s/pattern/string/修飾符:查找並替換,默認只替換每行中第一次被模式匹配到的字符串
        加修飾符
         g:全局替換,如:s/pattern/string/g
         i:忽略字符大小寫,如:s/pattern/string/i
    s///,s###,s@@@均可以,當所使用的分割符號與內容中顯示的相同時,需使用轉義字符轉義    
        \(\),\1,\2:成組匹配,\1表示匹配第一個‘(’,\2表示匹配第二個‘(’
    &:引用模式匹配到的整個串
介紹了那麼多,如今從咱們的系統中複製個文件,做爲咱們的測試文件,這裏,咱們複製/etc/inittab文件,並稍加修改,刪掉幾行,而後做爲測試文件使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cp /etc/inittab ./    #複製該文件到當前目錄下,這裏當前處於root家目錄下。
vim inittab     #編輯該文件,修改此文件,內容以下所示,其內容也可參看下邊的圖片
# inittab is only used by upstart for the default runlevel.
#
           #此處是一空行,沒有任何字符,就光空行添加代碼時會被刪掉,因此這裏加上備註,說明是一空交行,下面相同
# Individual runlevels are started by /etc/init/rc.conf
#
            #此處是一空行,沒有任何字符。該文件內容也看參見下邊的圖片
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:

 

 

用複製並修過的inittab文件做爲測試文件,舉幾個例子:面試

1
[root@www ~] # sed '1,3d' inittab:表示刪除文件的第一到第三行

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[root@www ~] # sed '3,$d' inittab   #表示刪除模式空間中的第三到最後一行
# inittab is only used by upstart for the default runlevel.
#
[root@www ~] # sed '/run/d' inittab     #表示刪除被run匹配到的行
#
#
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:
[root@www ~] # sed '/^#/d' inittab     #表示刪除文件中以#開頭的行
id :3:initdefault:
[root@www ~] # sed -n '/^\//p' inittab    #顯示以/開頭的行,由於沒有這樣的行,故不顯示任何信息
[root@www ~] # sed '/^#/p' inittab        #顯示以#開頭的行,能夠看到被匹配到的行,均顯示了兩遍,這是由於sed處理時會把處理的信息輸出
# inittab is only used by upstart for the default runlevel.
# inittab is only used by upstart for the default runlevel.
#
#
# Individual runlevels are started by /etc/init/rc.conf
# Individual runlevels are started by /etc/init/rc.conf
#
#
# Default runlevel. The runlevels used are:
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   3 - Full multiuser mode
#   4 - unused
#   4 - unused
#   5 - X11
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#   6 - reboot (Do NOT set initdefault to this)
#
#
id :3:initdefault:
[root@www ~] # sed -n '/^#/p' inittab     #顯示以#開頭的行,使用-n選項表示僅顯示匹配到的行
# inittab is only used by upstart for the default runlevel.
#
# Individual runlevels are started by /etc/init/rc.conf
#
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#

 

爲了後邊的演示,建立文件test,添加以下內容:
Welcome to my linux!
This is my world.
How are you?

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
vim test    #編輯該文件添加以下內容:
Welcome to my linux!
This is my world.
How are you?
[root@www ~] # sed '2r ./test' inittab    #表示將test文件中的內容添加到inittab文件中,且從第二行日後開始添加
# inittab is only used by upstart for the default runlevel.
#
Welcome to my linux!              #新添加的三行內容
This is my world.
How are you?
# Individual runlevels are started by /etc/init/rc.conf
#
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:
[root@www ~] # sed '1,2r ./test' inittab    #表示將test文件中的內容添加到inittab文件中,且分別 添加在第一和第二行後邊
# inittab is only used by upstart for the default runlevel.
Welcome to my linux!              #新添加的三行內容
This is my world.
How are you?
#
Welcome to my linux!                    #新添加的三行內容
This is my world.
How are you?
# Individual runlevels are started by /etc/init/rc.conf
#
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:
[root@www ~] # sed 's/linux/LINUX/g' test     #查找該文件中的字符串,而後替換爲指定的字符串
Welcome to my LINUX!                #能夠看到以替換爲大寫的linux
This is my world.
How are you?
[root@www ~] # sed 's/y.u/&r/g' test    #查找指定的字符串,並將其替換爲在其後加上r,分隔符采用/
Welcome to my linux!
This is my world.
How are your?
[root@www ~] # sed 's@y.u@&r@g' test     #意義同上,分隔符采用@
Welcome to my linux!
This is my world.
How are your?
[root@www ~] # sed 's#y.u#&r#g' test      #意義同上,分隔符采用#
Welcome to my linux!
This is my world.
How are your?

 

sed練習;正則表達式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
一、刪除 /etc/grub .conf文件中行首的空白符;
       sed  -r 's/^[[:space:]]+//' /etc/grub .conf
二、替換 /etc/inittab 文件中「 id :3:initdefault:」一行中的數字爲5;
      sed 's/\(id:\)[0-9]\(:initdefault:\)/\15\2/g' /etc/inittab
三、刪除 /etc/inittab 文件中的空白行;
      sed '/^$/d' /etc/inittab
四、刪除 /etc/inittab 文件中開頭的 #號;
      sed 's/^#//g' /etc/inittab
五、刪除某文件中開頭的 #號及其後面的空白字符,但要求#號後面必須有空白符;
      sed 's/^#[[:space:]]\{1,\}//g' /etc/inittab     或者
      sed  -r 's/^#[[:space:]]+//g' /etc/inittab
六、刪除某文件中以空白字符後面跟 #類的行中的開頭的空白字符及#
      sed -r 's/^[[:space:]]+#//g' /etc/inittab
七、取出一個文件路徑的目錄名稱;
      echo "/etc/rc.d/abc/edu/" | sed -r 's@^(/.*/)[^/]+/?@\1@g'        #因sed支持擴展正則表達式,在擴展正則表達式中,+表示匹配其前面的字符至少1次
八、取出一個文件路徑的最後一個文件名;
      echo "/etc/rc.d/abc/edu/" | sed -r 's@^/.*/([^/]+)/?@\1@g'

awk

awk是一種優良的文本處理工具,LinuxUnix環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操做語言(其名稱得自於它的創始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母)的最大功能取決於一我的所擁有的知識。AWK提供了極其強大的功能:能夠進行正則表達式的匹配,樣式裝入、流控制、數學運算符、進程控制語句甚至於內置的變量和函數。它具有了一個完整的語言所應具備的幾乎全部精美特性。實際上AWK的確擁有本身的語言:AWK程序設計語言,三位建立者已將它正式定義爲「樣式掃描和處理語言」。它容許您建立簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其餘的功能。最簡單地說,AWK是一種用於處理文本的編程語言工具。咱們如今使用最多的是gawk,gawk是AWK的GNU版本。
sql

使用格式:
# awk [options] 'script' file1, file2, ...
# awk [options] 'PATTERN { action }' file1, file2, ...

awk的輸出:print和printf
1、print
print的使用格式:
    print item1, item2, ...
要點:
一、各項目之間使用逗號隔開,而輸出時則以空白字符分隔;
二、輸出的item能夠爲字符串或數值、當前記錄的字段(如$1)、變量或awk的表達式;數值會先轉換爲字符串,然後再輸出;
三、print命令後面的item能夠省略,此時其功能至關於print $0, 所以,若是想輸出空白行,則須要使用print "";

例子:
1
2
awk 'BEGIN { print "line one\nline two\nline three" }'
awk -F: '{ print $1, $7 }' /etc/passwd     #等價於:awk -v FS=: '{print $1,$7}' /etc/passwd

 

2、awk變量shell

2.1 awk內置變量之記錄變量:
FS: field separator,字段分隔符,默認是空白字符;
RS: Record separator,記錄分隔符,默認是換行符;
OFS: Output Filed Separator,輸出字段分隔符
ORS:Output Row Separator,輸出行分隔符

一塊兒來看一個示例:express

 

1
2
3
4
5
vim test .txt   #編輯該文件,添加以下兩行信息做爲示例使用
welcome to redhat linux.
how are you?
[root@www ~] # awk 'BEGIN{OFS="#"} {print $1,$2}' test.txt    #指定輸出時的分隔符
[root@www ~] # awk 'BEGIN{OFS="#"} {print $1,"hello",$2}' test.txt   #指定輸出時的分隔符,並添加顯示的內容
上邊兩個命令的顯示效果以下所示:

1
2
3
4
5
6
7
8
9
[root@www ~] # awk -v FS=:  -v OFS=# '{print $1,$7}' /etc/passwd    #以:爲字段分隔符,以#號爲輸出分隔符,顯示該文件的第一及第七字段的值,這裏僅貼出部分顯示內容
root #/bin/bash
bin #/sbin/nologin
daemon #/sbin/nologin
adm #/sbin/nologin
lp #/sbin/nologin
sync #/bin/sync
shutdown #/sbin/shutdown
halt #/sbin/halt
2.2 awk內置變量之數據變量:
NR: The number of input records,awk命令所處理的記錄數;若是有多個文件,這個數目會把處理的多個文件中行統一計數;
NF:Number of Field,當前記錄的字段個數,有時可用來表示最後一個字段
FNR: 與NR不一樣的是,FNR用於記錄正處理的行是當前這一文件中被總共處理的行數;
ARGV: 數組,保存命令行自己這個字符串,如awk '{print $0}' a.txt b.txt這個命令中,ARGV[0]保存awk,ARGV[1]保存a.txt;
ARGC: awk命令的參數的個數;
FILENAME: awk命令所處理的文件的名稱;
ENVIRON:當前shell環境變量及其值的關聯數組;
如:
1
2
awk 'BEGIN{print ENVIRON["PATH"]}'
awk '{print $NF}' test .txt

2.3 用戶自定義變量
gawk容許用戶自定義本身的變量以便在程序代碼中使用,變量名命名規則與大多數編程語言相同,只能使用字母、數字和下劃線,且不能以數字開頭。gawk變量名稱區分字符大小寫。

2.3.1 在腳本中賦值變量
在gawk中給變量賦值使用賦值語句進行,例如:
1
2
[root@www ~] # awk 'BEGIN{var="variable testing";print var}'   #給變量賦值,並輸出變量的值,下邊是顯示效果
variable testing

2.3.2 在命令行中使用賦值變量
gawk命令也能夠在「腳本」外爲變量賦值,並在腳本中進行引用。例如,上述的例子還能夠改寫爲:
1
2
[root@www ~] # awk -v var="variable testing" 'BEGIN{print var}'     #與上述的例子同樣,顯示效果以下
variable testing

3、printf
printf命令的使用格式:
printf format, item1, item2, ...
要點:
一、其與print命令的最大不一樣是,printf須要指定格式;
二、format用於指定後面的每一個item的輸出格式;
三、printf語句不會自動打印換行,須要顯式使用\n換行。

format格式的指示符都以%開頭,後跟一個字符;以下:
%c: 顯示字符的ASCII碼;
%d, %i:十進制整數;
%e, %E:科學計數法顯示數值;
%f: 顯示浮點數;
%g, %G: 以科學計數法的格式或浮點數的格式顯示數值;
%s: 顯示字符串;
%u: 無符號整數;
%%: 顯示%自身;

修飾符:
N: 顯示寬度;
-: 左對齊;
+:顯示數值符號;
例子:
1
awk -F: '{printf "%-15s%i\n",$1,$3}' /etc/passwd      #使用printf顯示該文件中的第一列和第三列,要求第一列左對齊且佔用15個字符寬度,第二列顯示十進制整數,顯示效果以下所示:

 

4、輸出重定向

使用格式:
print items > output-file
print items >> output-file
print items | command
特殊文件描述符:
/dev/stdin:標準輸入
/dev/sdtout: 標準輸出
/dev/stderr: 錯誤輸出
/dev/fd/N: 某特定文件描述符,如/dev/stdin就至關於/dev/fd/0;
例子:
1
awk -F: '{printf "%-15s %i\n",$1,$3 > "/dev/stderr" }' /etc/passwd    #顯示效果與上述例子同樣,只不過這裏是重定向到錯誤輸出,而後顯示

6、awk的操做符:
6.1 算術操做符:
-x:負值
+x:轉換爲數值;
x^y:x的y次方
x**y: x的y次方
x*y:乘法
x/y:除法
x+y:加法
x-y:減法
x%y:取餘

6.2 字符串操做符:
只有一個,並且不用寫出來,用於實現字符串鏈接;
1
2
[root@www ~] # awk 'BEGIN{print "A" "B"}'     #鏈接A和B兩個字符,使其成爲一個字符串,顯示效果以下所示:
AB

6.3 賦值操做符:
=
+=
-=
*=
/=
%=
^=
**=
++
--

須要注意的是,若是某模式爲=號,此時使用/=/可能會有語法錯誤,應以/[=]/替代;

6.4 布爾值
awk中,任何非0值或非空字符串都爲真,反之就爲假;

6.5 比較操做符:
x < y     True if x is less than y.
x <= y     True if x is less than or equal to y.
x > y     True if x is greater than y.
x >= y     True if x is greater than or equal to y.
x == y     True if x is equal to y.
x != y     True if x is not equal to y.
x ~ y     True if the string x matches the regexp denoted by y. 若是字符串x被y表示的正則表達式匹配,則爲真;
x !~ y     True if the string x does not match the regexp denoted by y. 若是字符串x不被y表示的正則表達式匹配,則爲真;
subscript in array       True if the array array has an element with the subscript subscript.

如:
1
2
3
[root@www ~] # awk -F: '$1 ~ /^root/{print $1,$3,$4,$NF}' /etc/passwd    #顯示該文件中以root開頭的行的第一列、第三列、第四列和最後一列,顯示效果以下所示:
root 0 0 /bin/bash
[root@www ~] # awk -F: '$3>=400{printf "%-15s%-10i%s\n",$1,$3,$NF}' /etc/passwd #顯示UID大於400的行的第一列、第三列和最後一列

6.7 表達式間的邏輯關係符:
&&
||

6.8 條件表達式:
selector?if-true-exp:if-false-exp

6.9 函數調用:
function_name (para1,para2)

七 awk的模式:
awk 'program' input-file1 input-file2 ...
其中的program爲:
pattern { action }
pattern { action }
...

7.1 常見的pattern類型:
一、Regexp: 正則表達式,格式爲/regular expression/
    如:
1
2
3
4
5
[root@www ~] # awk -F: '/bash/{print $0}' /etc/passwd    #在/etc/passwd中查找有bash的行,並顯示
root:x:0:0:root: /root : /bin/bash
nginx:x:496:493:: /home/nginx : /bin/bash
mysql:x:495:492:: /home/mysql : /bin/bash
wpuser:x:494:491:: /home/wpuser : /bin/bash

二、expresssion: 表達式,其值非0或爲非空字符時知足條件,如:$1 ~ /foo/ 或 $1 == "lq2419",用運算符~(匹配)和~!(不匹配)。
    如:
1
2
3
awk -F: '$3>=500{printf "%-15s%s\n",$1,$3}' /etc/passwd
awk -F: '$1 ~ /root/{print $1,$3}' /etc/passwd
      等價於: awk -F: '$1=="root"{print $1,$3}' /etc/passwd

三、Ranges: 指定的匹配範圍,格式爲pat1,pat2

四、BEGIN/END:特殊模式,僅在awk命令執行前運行一次或結束前運行一次
    如:
1
2
3
4
5
6
7
8
9
[root@www ~] # awk -F: 'BEGIN{print "Username       UID"}$3>=400{printf "%-15s%s\n",$1,$3}' /etc/passwd       #上式表示對於該文件,在開始比較前先輸出username和UID做爲題頭,而後,輸出UID大於400的行的第一列和第三列
Username       UID
rtkit          499
pulse          498
saslauth       497
nfsnobody      65534
nginx          496
mysql          495
wpuser         494
如今我想輸出/etc/passwd文件中的第一列,那麼,有多少種方法能夠實現呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
有三中方式都可以實現,命令及顯示效果以下:
[root@www ~] #  awk -v FS=: '{print $1}' /etc/passwd    #使用-v選項和FS指定分隔符,而後顯示
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
[root@www ~] # awk -F: '{print $1}' /etc/passwd       #直接使用-F選項指定分隔符,而後顯示
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
[root@www ~] # awk 'BEGIN{FS=":"}{print $1}' /etc/passwd    #使用BEGIN,在運行前指定分隔符,而後顯示
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp

五、Empty(空模式):匹配任意輸入行;

7.2 常見的Action
一、Expressions:
二、Control statements
三、Compound statements
四、Input statements
五、Output statements


/正則表達式/:使用通配符的擴展集。
關係表達式:能夠用下面運算符表中的關係運算符進行操做,能夠是字符串或數字的比較,如$2>$1選擇第二個字段比第一個字段長的行。

模式匹配表達式:
模式,模式:指定一個行的範圍。該語法不能包括BEGIN和END模式。
BEGIN:讓用戶指定在第一條輸入記錄被處理以前所發生的動做,一般可在這裏設置全局變量。
END:讓用戶在最後一條輸入記錄被讀取以後發生的動做。

八 控制語句:
8.1 if-else
語法:if (condition) {then-body} else {[ else-body ]}
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@www ~] # awk -F: '{if ($1=="root") print $1, "Admin"; else print $1, "Common User"}' /etc/passwd    #判斷若是第一個字段是root,則顯示是admin,不然顯示是common user,顯示結果以下所示:
root Admin
bin Common User
daemon Common User
adm Common User
lp Common User
sync Common User
shutdown Common User
halt Common User
[root@www ~] # awk -F: '{if ($1=="root") printf "%-15s%s\n", $1,"Admin"; else printf "%-15s%s\n", $1, "Common User"}' /etc/passwd          #顯示效果同上,只不過這裏使用printf,顯示定義顯示的格式
root             Admin
bin              Common User
daemon           Common User
adm              Common User
lp               Common User
sync             Common User
shutdown         Common User
halt             Common User
mail             Common User
uucp             Common User
[root@www ~] # awk -F: -v sum=0 '{if ($3>=400) sum++}{if ($3>=400) printf "%-15s%i\n",$1,$3}END{print "Sum = "sum;}' /etc/passwd                #定義變量sum=0,而後判斷若是UID大於400,讓sum自加,而且若是UID大於等於400的顯示其用戶名和UID,結束前輸出sum的值
rtkit             499
pulse             498
saslauth          497
nfsnobody         65534
nginx             496
mysql             495
wpuser            494
Sum = 7

8.2 while
語法: while (condition){statement1; statment2; ...}
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@www ~] # awk -F: -v i=1 '{while (i<=7) {print $i;i++}}' /etc/passwd    #使用-v選項顯示定義變量i=1,當i小於等於7時循環結束,而後,輸出第一個字段到第七個字段,當i爲7時,正好輸出的是第一行的7個字段的值
root
x
0
0
root
/root
/bin/bash
[root@www ~] # awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd    #定義變量i,先判斷,當i小於等於3時,輸出第一到第三個字段的值,所處理的數據時該文件中的每一行數據,而不只僅是第一行。這裏須要注意與上述命令的 區別
root
x
0
bin
x
1
daemon
x
2
adm
x
3
lp
x
4

8.3 do-while
語法: do {statement1, statement2, ...} while (condition)
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@www ~] # awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd    #意義同上,顯示效果雖與上述相同,但與while不一樣的是,do-while是先執行一趟,而後再判斷是否知足條件,也就是說無論條件是否知足,都會先 執行一趟;而while中若是條件不知足,則一趟也不會執行
root
x
0
bin
x
1
daemon
x
2
adm
x
3
lp
x
4

8.4 for
語法: for ( variable assignment; condition; iteration process) { statement1, statement2, ...}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@www ~] # awk -F: '{for(i=1;i<=3;i++) print $i}' /etc/passwd     #使用for循環,輸出各行的前三個字段
root
x
0
bin
x
1
daemon
x
2
adm
x
3
lp
x
4

for循環還能夠用來遍歷數組元素:
語法: for (i in array) {statement1, statement2, ...}
1
2
3
4
5
6
[root@www ~] # awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}' /etc/passwd      #匹配最後一個字段不空的行,把最後一段當作數組下標,輸出各下標的值,及各下標對應的個數,各下標的個數保存在數組中
          /bin/sync :1
          /bin/bash :4
      /sbin/nologin :29
         /sbin/halt :1
     /sbin/shutdown :1


8.5 case
語法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}

8.6 break 和 continue
經常使用於循環或case語句中

8.7 next
提早結束對本行文本的處理,並接着處理下一行;例如,下面的命令將顯示其ID號爲奇數的用戶:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@www ~] # awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd    #UID號對2取餘,若是爲0,直接處理下一行,不然,輸出用戶名和UID號,顯示效果以下所示:
bin 1
adm 3
sync 5
halt 7
operator 11
gopher 13
nobody 99
dbus 81
usbmuxd 113
vcsa 69
rtkit 499
saslauth 497
postfix 89
abrt 173
rpcuser 29
mysql 495

九 awk中使用數組
9.1 數組
array[index-expression]
index-expression可使用任意字符串;須要注意的是,若是某數據組元素事先不存在,那麼在引用其時,awk會自動建立此元素並初始化爲空串;所以,要判斷某數據組中是否存在某元素,須要使用index in array的方式。

要遍歷數組中的每個元素,須要使用以下的特殊結構:
for (var in array) { statement1, ... }
其中,var用於引用數組下標,而不是元素值;
例子:
1
2
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
每出現一被/^tcp/模式匹配到的行,數組S[$NF]就加1,NF爲當前匹配到的行的最後一個字段,此處用其值作爲數組S的元素索引
1
2
3
4
5
6
7
8
9
10
11
[root@www ~] # awk '{IP[$1]++}END{for (A in IP) printf "%-20s%s\n",A,IP[A]}' /var/log/nginx/access.log     #用法與上一個例子相同,用於統計某日誌文件中IP地的訪問量
172.16.32.30         3
172.16.32.50         31596
172.16.32.52         408
192.168.0.239        1886
172.16.32.0          1010
[root@www ~] # awk 'BEGIN{A["m"]="hello";A["n"]="world";print A["m"],A["n"]}'     #開始前對數組賦值,而後輸出數組的值
hello world
[root@www ~] # awk 'BEGIN{A["m"]="hello";A["n"]="world";for (B in A) print A[B]}'      #在開始前對數組賦值,而後使用for循環,把B當作下標,依次輸出數組中的值
hello
world

9.2 刪除數組變量
從關係數組中刪除數組索引須要使用delete命令。使用格式爲:
delete  array[index]

10、awk的內置函數
split(string, array [, fieldsep [, seps ] ])
功能:將string表示的字符串以fieldsep爲分隔符進行分隔,並將分隔後的結果保存至array爲名的數組中;數組下標爲從0開始的序列;
1
netstat -ant | awk '/:22\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50  #顯示效果以下所示:
length([string])
功能:返回string字符串中字符的個數;
substr(string, start [, length])
功能:取string字符串中的子串,從start開始,取length個;start從1開始計數;
system(command)
功能:執行系統command並將結果返回至awk命令
systime()
功能:取系統當前時間
tolower(s)
功能:將s中的全部字母轉爲小寫
toupper(s)
功能:將s中的全部字母轉爲大寫

11、用戶自定義函數
自定義函數使用function關鍵字。格式以下:
function F_NAME([variable])
{
    statements
}

函數還可使用return語句返回值,格式爲「return value」。


在 最後,介紹個面試中常被問到的關於awk的一個問題,順便給出幾個好玩的awk命令。有時候面試的時候,會被問到,使用awk編寫腳本打印出乘法口訣,牛 人固然以爲這小菜一碟,可是,像咱們這些菜鳥,可就該抓耳撓腮了,本人通過上網搜索,加上本身嘗試,寫出了該腳本。先附上腳本及打印效果,以供參考。
一、乘法口訣
1
2
3
4
5
6
7
8
9
10
11
12
vim cfkj.sh   #編輯該文件,輸入以下內容:
#!/bin/awk -f
BEGIN{
         for (i=1;i<=9;i++)
         {
         for (m=1;m<=i;m++)
                 {
                         printf m "*" i "=" m*i "  "
                 }
         print
         }
}

 

二、打印圖案

接 觸過C語言的都知道,咱們在剛開始學C語言的時候,有時候爲了讓你可以學下去,特別是在譚浩強版的C程序設計叢書中,會有不少課後習題,讓你用C語言實現 打印一些圖案等,甚至是一些有意思的像編程實現使各行、各列以及對角線之和都相等之類的圖標等等。那若是如今讓你用awk來實現,打印一個圖案,又該如何 實現呢?比方說,使用awk打印以下圖案。
         *
        ***
      *****
     *******
對於這個咱們又該如何實現呢?其實,可以使用以下命令實現打印此圖案。
1
awk 'BEGIN {for(i=1;i<=4;i++) {for(j=1;j<=10-i;j++) {printf " ";}for(j=1;j<=(2*i-1);j++) {printf "*";}printf "\n";}}'

三、使用數字打印中心對稱圖形
這個就有點難度了。本人也沒有想出來,這個是一個朋友給個人,以爲好玩,就拿出來跟你們分享一下。這裏直接給出命令及顯示效果了,就不弔各位胃口了。
1
2
echo 15| awk '{x=8; for (i=1;i<$0;i++){ for (j=1;j<=3*($0-i)-(x>0?x:0);j++) printf " " ; for (k=i;k>=1;k--) printf "%d " ,k; for (l=2;l<=i;l++) printf "%d " ,l; printf "\n" ;x--};\
for (i=1;i<=$0;i++){ for (j=1;j<=(i<=$0-10+1?3*(i-1):3*(i-1)+2-(i-$0%10-10*int(($0-10) /10 )));j++) printf " " ; for (k=$0-i+1;k>=1;k--) printf "%d " ,k; for (l=2;l<=$0-i+1;l++) printf "%d " ,l; printf "\n" }}'
相關文章
相關標籤/搜索