1. 程式人生 > >2018-1-17 6周3次課

2018-1-17 6周3次課

shu 忽略 his sco cal system tab 常見 腳本文件

9.6/9.7 awk

技術分享圖片

awk工具,比sed更豐富的功能它支持了分段。

技術分享圖片

指定分隔符然後把第一段打印出來如下:

技術分享圖片

註:如果想把第2和第3也打印出來直接在$1的後面加個逗號輸入$2,$3即可

指定分隔符然後把所有段打印出來如下:

技術分享圖片

awk直接打印全部內容如下:

技術分享圖片

註:如果awk忽略了-F,也就是沒有指定分隔符他默認的將會以空格或者空白字符為分割符去打印

awk匹配功能如下
技術分享圖片

打印第一段OO的行如下

技術分享圖片

同樣支持正則表達式如下

技術分享圖片

awk支持多個表達式一起寫如下:

匹配root把第一段和第二段打印出來然後緊接著在匹配test的第一段和第二段打印出來如下操作

技術分享圖片

也可以這樣寫如下

技術分享圖片

針對數學預算表達式比如$3也就是第3段等於0的還有第三段大預定於500的,加上雙引號和不加雙引號是不同的如下:

技術分享圖片

技術分享圖片

第7段不等於/sbin/nologin/的如果是字符串需要加雙引號

技術分享圖片


~~~~~~``~~~~~~
































技術分享圖片

兩個字段相互的比較。

技術分享圖片

兩個字段等於

技術分享圖片

兩個條件一起用,並且&&

技術分享圖片

除了並且還可以或者||
技術分享圖片

OFS內置的變量
技術分享圖片

NR表示行,NF表示段

技術分享圖片

技術分享圖片

前10行打印出來

技術分享圖片

技術分享圖片


擴展

grep / egrep

阿銘在前面的內容中多次提到並用到grep命令,可見它的重要性。所以好好學習一下這個重要的命令吧。你要知道的是grep連同下面講的sed, awk都是針對文本的行才操作的。

語法: grep [-cinvABC] ‘word‘ filename

-c :打印符合要求的行數

-i :忽略大小寫

-n :在輸出符合要求的行的同時連同行號一起輸出

-v :打印不符合要求的行

-A :後跟一個數字(有無空格都可以),例如 –A2則表示打印符合要求的行以及下面兩行

-B :後跟一個數字,例如 –B2 則表示打印符合要求的行以及上面兩行

-C :後跟一個數字,例如 –C2 則表示打印符合要求的行以及上下各兩行

[root@localhost ~]# grep -A2 ‘halt‘ /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
把包含 ‘halt’ 的行以及這行下面的兩行都打印出。

[root@localhost ~]# grep -B2 ‘halt‘ /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
把包含 ‘halt’ 的行以及這行上面的兩行都打印出。

[root@localhost ~]# grep -C2 ‘halt‘ /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
把包含 ‘halt’ 的行以及這行上面和下面的各兩行都打印出。

下面阿銘舉幾個典型實例幫你更深刻的理解grep.

過濾出帶有某個關鍵詞的行並輸出行號
[root@localhost ~]# grep -n ‘root‘ /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
11:operator:x:11:0:operator:/root:/sbin/nologin
過濾不帶有某個關鍵詞的行,並輸出行號
[root@localhost ~]# grep -nv ‘nologin‘ /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
26:test:x:511:511::/home/test:/bin/bash
27:test1:x:512:511::/home/test1:/bin/bash
過濾出所有包含數字的行
[root@localhost ~]# grep ‘[0-9]‘ /etc/inittab

upstart works, see init(5), init(8), and initctl(8).

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@localhost ~]# grep -v ‘[0-9]‘ /etc/inittab

inittab is only used by upstart for the default runlevel.

#

ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.

#

System initialization is started by /etc/init/rcS.conf

#

Individual runlevels are started by /etc/init/rc.conf

#

Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf

#

Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,

with configuration in /etc/sysconfig/init.

#

For information on how to write upstart event handlers, or how

#

Default runlevel. The runlevels used are:

#
把所有以 ‘#’ 開頭的行去除
[root@localhost ~]# grep -v ‘^#‘ /etc/inittab
id:3:initdefault:
去除所有空行和以 ‘#’ 開頭的行
[root@localhost ~]# grep -v ‘^#‘ /etc/crontab |grep -v ‘^$‘
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
在正則表達式中, “^” 表示行的開始, “$” 表示行的結尾,那麽空行則可以用 “^$” 表示,如何打印出不以英文字母開頭的行呢?

[root@localhost ~]# vim test.txt
[root@localhost ~]# cat test.txt
123
abc
456

abc2323
#laksdjf
Alllllllll
阿銘先在test.txt中寫幾行字符串,用來做實驗。

[root@localhost ~]# grep ‘^[^a-zA-Z]‘ test.txt
123
456
#laksdjf
[root@localhost ~]# grep ‘[^a-zA-Z]‘ test.txt
123
456
abc2323
#laksdjf
在前面阿銘也提到過這個 ‘[ ]’ 的應用,如果是數字的話就用[0-9]這樣的形式,當然有時候也可以用這樣的形式[15]即只含有1或者5,註意,它不會認為是15。如果要過濾出數字以及大小寫字母則要這樣寫[0-9a-zA-Z]。另外[ ]還有一種形式,就是[^字符] 表示除[ ]內的字符之外的字符。

過濾任意一個字符與重復字符
[root@localhost ~]# grep ‘r..o‘ /etc/passwd
operator:x:11:0:operator:/root:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
. 表示任意一個字符,上例中,就是把符合r與o之間有兩個任意字符的行過濾出來, * 表示零個或多個前面的字符。

[root@localhost ~]# grep ‘ooo‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
‘ooo
’ 表示oo, ooo, oooo ... 或者更多的 ‘o’ 現在你是否想到了 ‘.*’ 這個組合表示什麽意義?

[root@localhost ~]# grep ‘.‘ /etc/passwd |wc -l
27
[root@localhost ~]# wc -l /etc/passwd
27 /etc/passwd
‘.
’ 表示零個或多個任意字符,空行也包含在內。

指定要過濾字符出現的次數
[root@localhost ~]# grep ‘o{2}‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
這裏用到了{ },其內部為數字,表示前面的字符要重復的次數。上例中表示包含有兩個o 即 ‘oo’ 的行。註意,{ }左右都需要加上脫意字符 ‘\’, 另外,使用{ }我們還可以表示一個範圍的,具體格式是 ‘{n1,n2}’ 其中n1<n2,表示重復n1到n2次前面的字符,n2還可以為空,則表示大於等於n1次。

上面部分講的grep,另外阿銘常常用到egrep這個工具,簡單點講,後者是前者的擴展版本,我們可以用egrep完成grep不能完成的工作,當然了grep能完成的egrep完全可以完成。如果你嫌麻煩,egrep了解一下即可,因為grep的功能已經足夠可以勝任你的日常工作了。下面阿銘介紹egrep不用於grep的幾個用法。為了試驗方便,阿銘把test.txt 編輯成如下內容:

rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
篩選一個或一個以上前面的字符
[root@localhost ~]# egrep ‘o+‘ test.txt
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep ‘oo+‘ test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep ‘ooo+‘ test.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
和grep 不同的是,egrep這裏是使用’+’的。

篩選零個或一個前面的字符
[root@localhost ~]# egrep ‘o?‘ test.txt
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# egrep ‘ooo?‘ test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep ‘oooo?‘ test.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
篩選字符串1或者字符串2
[root@localhost ~]# egrep ‘aaa|111|ooo‘ test.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
egrep中( )的應用
[root@localhost ~]# egrep ‘r(oo|at)o‘ test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
用( )表示一個整體,例如(oo)+就表示1個 ‘oo’ 或者多個 ‘oo’

[root@localhost ~]# egrep ‘(oo)+‘ test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
sed工具的使用

grep工具的功能其實還不夠強大,grep實現的只是查找功能,而它卻不能實現把查找的內容替換掉。以前用vim的時候,可以查找也可以替換,但是只局限於在文本內部來操作,而不能輸出到屏幕上。sed工具以及下面要講的awk工具就能實現把替換的文本輸出到屏幕上的功能了,而且還有其他更豐富的功能。sed和awk都是流式編輯器,是針對文檔的行來操作的。

打印某行
sed -n ‘n‘p filename 單引號內的n是一個數字,表示第幾行:

[root@localhost ~]# sed -n ‘2‘p /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
要想把所有行都打印出來可以使用 sed -n ‘1,$‘p filename

[root@localhost ~]# sed -n ‘1,$‘p test.txt
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
也可以指定一個區間:

[root@localhost ~]# sed -n ‘1,3‘p test.txt
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
打印包含某個字符串的行
[root@localhost ~]# sed -n ‘/root/‘p test.txt
operator:x:11:0:operator:/root:/sbin/nologin
grep中使用的特殊字符,如 ^ $ . * 等同樣也能在sed中使用

[root@localhost ~]# sed -n ‘/^1/‘p test.txt
1111111111111111111111111111111
[root@localhost ~]# sed -n ‘/in$/‘p test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
[root@localhost ~]# sed -n ‘/r..o/‘p test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# sed -n ‘/ooo*/‘p test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
-e可以實現多個行為
[root@localhost ~]# sed -e ‘1‘p -e ‘/111/‘p -n test.txt
rot:x:0:0:/rot:/bin/bash
1111111111111111111111111111111
刪除某行或者多行
[root@localhost ~]# sed ‘1‘d test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed ‘1,3‘d test.txt
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed ‘/oot/‘d test.txt
rot:x:0:0:/rot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
‘d’ 這個字符就是刪除的動作了,不僅可以刪除指定的單行以及多行,而且還可以刪除匹配某個字符的行,另外還可以刪除從某一行一直到文檔末行。

替換字符或字符串
[root@localhost ~]# sed ‘1,2s/ot/to/g‘ test.txt
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
上例中的 ‘s’ 就是替換的命令, ‘g’ 為本行中全局替換,如果不加 ‘g’ 只換該行中出現的第一個。除了可以使用 ‘/’ 作為分隔符外,還可以使用其他特殊字符例如 ‘#’ 或者 ‘@’ 都沒有問題。

[root@localhost ~]# sed ‘s#ot#to#g‘ test.txt
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed ‘s@ot@to@g‘ test.txt
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
現在思考一下,如何刪除文檔中的所有數字或者字母?

[root@localhost ~]# sed ‘s/[0-9]//g‘ test.txt
rot:x:::/rot:/bin/bash
operator:x:::operator:/root:/sbin/nologin
operator:x:::operator:/rooot:/sbin/nologin
roooot:x:::/rooooot:/bin/bash

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[0-9]表示任意的數字。這裏你也可以寫成[a-zA-Z]甚至[0-9a-zA-Z]

[root@localhost ~]# sed ‘s/[a-zA-Z]//g‘ test.txt
::0:0:/://
::11:0::/://
::11:0::/://
::0:0:/://
1111111111111111111111111111111
調換兩個字符串的位置
[root@localhost ~]# sed ‘s/(rot)(.*)(bash)/\3\2\1/‘ test.txt
bash:x:0:0:/rot:/bin/rot
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
這個就需要解釋一下了,上例中用 () 把所想要替換的字符括起來成為一個整體,因為括號在sed中屬於特殊符號,所以需要在前面加脫意字符 ‘’, 替換時則寫成 ‘1’, ‘‘2’, ‘‘3’ 的形式。除了調換兩個字符串的位置外,阿銘還常常用到在某一行前或者後增加指定內容。

[root@localhost ~]# sed ‘s/^.*$/123&/‘ test.txt
123rot:x:0:0:/rot:/bin/bash
123operator:x:11:0:operator:/root:/sbin/nologin
123operator:x:11:0:operator:/rooot:/sbin/nologin
123roooot:x:0:0:/rooooot:/bin/bash
1231111111111111111111111111111111
123aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
直接修改文件的內容
[root@localhost ~]# sed -i ‘s/ot/to/g‘ test.txt
[root@localhost ~]# cat test.txt
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
這樣就可以直接更改test.txt文件中的內容了。由於這個命令可以直接把文件修改,所以在修改前最好先復制一下文件以免改錯。

sed常用到的也就上面這些了,只要你多加練習就能熟悉它了。為了能讓你更加牢固的掌握sed的應用,阿銘留幾個練習題,希望你能認真完成。

把/etc/passwd 復制到/root/test.txt,用sed打印所有行
打印test.txt的3到10行
打印test.txt 中包含 ‘root’ 的行
刪除test.txt 的15行以及以後所有行
刪除test.txt中包含 ‘bash’ 的行
替換test.txt 中 ‘root’ 為 ‘toor’
替換test.txt中 ‘/sbin/nologin’ 為 ‘/bin/login’
刪除test.txt中5到10行中所有的數字
刪除test.txt 中所有特殊字符(除了數字以及大小寫字母)
把test.txt中第一個單詞和最後一個單詞調換位置
把test.txt中出現的第一個數字和最後一個單詞替換位置
把test.txt 中第一個數字移動到行末尾
在test.txt 20行到末行最前面加 ‘aaa:’
阿銘希望你能盡量多想一想,答案只是用來作為參考的。

sed習題答案

  1. /bin/cp /etc/passwd /root/test.txt ; sed -n ‘1,$‘p test.txt
  2. sed -n ‘3,10‘p test.txt
  3. sed -n ‘/root/‘p test.txt
  4. sed ‘15,$‘d test.txt
  5. sed ‘/bash/‘d test.txt
  6. sed ‘s/root/toor/g‘ test.txt
  7. sed ‘s#sbin/nologin#bin/login#g‘ test.txt
  8. sed ‘5,10s/[0-9]//g‘ test.txt
  9. sed ‘s/[^0-9a-zA-Z]//g‘ test.txt
  10. sed ‘s/(^[a-zA-Z][a-zA-Z])([^a-zA-Z].)([^a-zA-Z])([a-zA-Z][a-zA-Z]*$)/\4\2\3\1/‘ test.txt
  11. sed ‘s#([^0-9][^0-9])([0-9][0-9])([^0-9].)([^a-zA-Z])([a-zA-Z][a-zA-Z]$)#\1\5\3\4\2#‘ test.txt
  12. sed ‘s#([^0-9][^0-9])([0-9][0-9])([^0-9].*$)#\1\3\2#‘ test.txt
  13. sed ‘20,$s/^.*$/aaa:&/‘ test.txt
    awk工具的使用

上面也提到了awk和sed一樣是流式編輯器,它也是針對文檔中的行來操作的,一行一行的去執行。awk比sed更加強大,它能做到sed能做到的,同樣也能做到sed不能做到的。awk工具其實是很復雜的,有專門的書籍來介紹它的應用,但是阿銘認為學那麽復雜沒有必要,只要能處理日常管理工作中的問題即可。何必讓自己的腦袋裝那麽東西來為難自己?畢竟用的也不多,即使現在教會了你很多,你也學會了,如果很久不用肯定就忘記了。鑒於此,阿銘僅介紹比較常見的awk應用,如果你感興趣的話,再去深入研究吧。

截取文檔中的某個段
[root@localhost ~]# head -n2 /etc/passwd |awk -F ‘:‘ ‘{print $1}‘
root
bin
解釋一下,-F 選項的作用是指定分隔符,如果不加-F指定,則以空格或者tab為分隔符。 Print為打印的動作,用來打印出某個字段。$1為第一個字段,$2為第二個字段,依次類推,有一個特殊的那就是$0,它表示整行。

[root@localhost ~]# head -n2 test.txt |awk -F‘:‘ ‘{print $0}‘
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
註意awk的格式,-F後緊跟單引號,然後裏面為分隔符,print的動作要用 { } 括起來,否則會報錯。print還可以打印自定義的內容,但是自定義的內容要用雙引號括起來。

[root@localhost ~]# head -n2 test.txt |awk -F‘:‘ ‘{print $1"#"$2"#"$3"#"$4}‘
rto#x#0#0
operator#x#11#0
匹配字符或字符串
[root@localhost ~]# awk ‘/oo/‘ test.txt
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
跟sed很類似吧,不過還有比sed更強大的匹配。

[root@localhost ~]# awk -F ‘:‘ ‘$1 ~/oo/‘ test.txt
roooto:x:0:0:/rooooto:/bin/bash
可以讓某個段去匹配,這裏的’~’就是匹配的意思,繼續往下看

[root@localhost ~]# awk -F ‘:‘ ‘/root/ {print $1,$3} /test/ {print $1,$3}‘ /etc/passwd
root 0
operator 11
test 511
test1 512
awk還可以多次匹配,如上例中匹配完root,再匹配test,它還可以只打印所匹配的段。

條件操作符
[root@localhost ~]# awk -F ‘:‘ ‘$3=="0"‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
awk中是可以用邏輯符號判斷的,比如 ‘==’ 就是等於,也可以理解為 ‘精確匹配’ 另外也有 >, ‘>=, ‘<, ‘<=, ‘!= 等等,值得註意的是,在和數字比較時,若把比較的數字用雙引號引起來後,那麽awk不會認為是數字,而認為是字符,不加雙引號則認為是數字。

[root@localhost ~]# awk -F ‘:‘ ‘$3>="500"‘ /etc/passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
user11:x:510:502:user11,user11‘s office,12345678,123456789:/home/user11:/sbin/nologin
test:x:511:511::/home/test:/bin/bash
test1:x:512:511::/home/test1:/bin/bash
在上面的例子中,阿銘本想把uid大於等於500的行打印出,但是結果並不是我們的預期,這是因為awk把所有的數字當作字符來對待了,就跟上一章中提到的 sort 排序原理一樣。

[root@localhost ~]# awk -F ‘:‘ ‘$7!="/sbin/nologin"‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
test:x:511:511::/home/test:/bin/bash
test1:x:512:511::/home/test1:/bin/bash
!= 為不匹配,除了針對某一個段的字符進行邏輯比較外,還可以兩個段之間進行邏輯比較。

[root@localhost ~]# awk -F ‘:‘ ‘$3<$4‘ /etc/passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
另外還可以使用 && 和 || 表示 “並且” 和 “或者” 的意思。

[root@localhost ~]# awk -F ‘:‘ ‘$3>"5" && $3<"7"‘ /etc/passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
user11:x:510:502:user11,user11‘s office,12345678,123456789:/home/user11:/sbin/nologin
test:x:511:511::/home/test:/bin/bash
test1:x:512:511::/home/test1:/bin/bash
也可以是或者

[root@localhost ~]# awk -F ‘:‘ ‘$3>"5" || $7=="/bin/bash"‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
user11:x:510:502:user11,user11‘s office,12345678,123456789:/home/user11:/sbin/nologin
test:x:511:511::/home/test:/bin/bash
test1:x:512:511::/home/test1:/bin/bash
awk的內置變量
awk常用的變量有:

NF :用分隔符分隔後一共有多少段

NR :行數

[root@localhost ~]# head -n3 /etc/passwd | awk -F ‘:‘ ‘{print NF}‘
7
7
7
[root@localhost ~]# head -n3 /etc/passwd | awk -F ‘:‘ ‘{print $NF}‘
/bin/bash
/sbin/nologin
/sbin/nologin
NF 是多少段,而$NF是最後一段的值, 而NR則是行號。

[root@localhost ~]# head -n3 /etc/passwd | awk -F ‘:‘ ‘{print NR}‘
1
2
3
我們可以使用行號作為判斷條件:

[root@localhost ~]# awk ‘NR>20‘ /etc/passwd
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
user11:x:510:502:user11,user11‘s office,12345678,123456789:/home/user11:/sbin/nologin
test:x:511:511::/home/test:/bin/bash
test1:x:512:511::/home/test1:/bin/bash
也可以配合段匹配一起使用:

[root@localhost ~]# awk -F ‘:‘ ‘NR>20 && $1 ~ /ssh/‘ /etc/passwd
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
awk中的數學運算
awk可以把段值更改:

[root@localhost ~]# head -n 3 /etc/passwd |awk -F ‘:‘ ‘$1="root"‘
root x 0 0 root /root /bin/bash
root x 1 1 bin /bin /sbin/nologin
root x 2 2 daemon /sbin /sbin/nologin
awk還可以對各個段的值進行數學運算:

[root@localhost ~]# head -n2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@localhost ~]# head -n2 /etc/passwd |awk -F ‘:‘ ‘{$7=$3+$4}‘
[root@localhost ~]# head -n2 /etc/passwd |awk -F ‘:‘ ‘{$7=$3+$4; print $0}‘
root x 0 0 root /root 0
bin x 1 1 bin /bin 2
當然還可以計算某個段的總和

[root@localhost ~]# awk -F ‘:‘ ‘{(tot=tot+$3)}; END {print tot}‘ /etc/passwd
2891
這裏的END要註意一下,表示所有的行都已經執行,這是awk特有的語法,其實awk連同sed都可以寫成一個腳本文件,而且有他們特有的語法,在awk中使用if判斷、for循環都是可以的,只是阿銘認為日常管理工作中沒有必要使用那麽復雜的語句而已。

[root@localhost ~]# awk -F ‘:‘ ‘{if ($1=="root") print $0}‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
基本上,正則表達的內容就這些了。但是阿銘要提醒你一下,阿銘介紹的這些僅僅是最基本的東西,並沒有提啊深入的去講sed和awk,但是完全可以滿足日常工作的需要,有時候也許你會碰到比較復雜的需求,如果真遇到了就去請教一下google吧。下面出幾道關於awk的練習題,希望你要認真完成。

用awk 打印整個test.txt (以下操作都是用awk工具實現,針對test.txt)
查找所有包含 ‘bash’ 的行
用 ‘:’ 作為分隔符,查找第三段等於0的行
用 ‘:’ 作為分隔符,查找第一段為 ‘root’ 的行,並把該段的 ‘root’ 換成 ‘toor’ (可以連同sed一起使用)
用 ‘:’ 作為分隔符,打印最後一段
打印行數大於20的所有行
用 ‘:’ 作為分隔符,打印所有第三段小於第四段的行
用 ‘:’ 作為分隔符,打印第一段以及最後一段,並且中間用 ‘@’ 連接 (例如,第一行應該是這樣的形式 ‘root@/bin/bash‘ )
用 ‘:’ 作為分隔符,把整個文檔的第四段相加,求和
awk習題答案

  1. awk ‘{print $0}‘ test.txt
  2. awk ‘/bash/‘ test.txt
  3. awk -F‘:‘ ‘$3=="0"‘ test.txt
  4. awk -F‘:‘ ‘$1=="root"‘ test.txt |sed ‘s/root/toor/‘
  5. awk -F‘:‘ ‘{print $NF}‘ test.txt
  6. awk -F‘:‘ ‘NR>20‘ test.txt
  7. awk -F‘:‘ ‘$3<$4‘ test.txt
  8. awk -F‘:‘ ‘{print $1"@"$NF}‘ test.txt
  9. awk -F‘:‘ ‘{(sum+=$4)}; END {print sum}‘ test.txt

2018-1-17 6周3次課