歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> SHELL編程 >> linux shell篇(五)正則表達式

linux shell篇(五)正則表達式

日期:2017/3/1 11:45:21   编辑:SHELL編程

一.正則表達式:

正則表達式 RE 、 Regular Expression

是一種字符模式,是在匹配文本時,使用一些特殊符號,匹配到用戶想要的東西

字符模式:

普通字符:沒有任何特殊含義的字符

元字符:具有特殊含義的字符 ^ $ * . [] () {}

正則表達式一般是夾在雙斜線之間的 如:/^abc/等

介紹正則表達式元字符

元字符 功能 例子 匹配結果

^ 行首定位符 /^root/ 匹配以root開頭的行

$ 行尾定位符 /sh$/ 匹配以sh結尾的行

. 匹配任意單個字符(除了換行符) /l.ve/ 匹配live、love、... ...

* 前導符

匹配0個或者多個它前面的模式 /l*ve/ 匹配ve、lve、llve、... ...

.* 匹配0到多個任意字符

[] 匹配一組字符中的任意一個 /l[ioIO]ve/ 匹配live、love、lIve、lOve

[x-y] 匹配一段范圍中的任意一個 /l[o-z]ve/ 匹配love、lpve、lqve、... ...、lzve

[0-9] 數字

[a-z] 小寫字母

[A-Z] 大寫字母

[a-z0-9] 小寫字母或數字

[-+*/] +-*/ 四則運算

[a-Z] 字母

[^] 表示取反 /^[^abc]ve/ 匹配除了ave、bve、cve以外的三個字符的字符串

[^0-9] 不是數字

\ 用於轉義元字符的 /93\.4/ 匹配93.4

\< 詞首定位符 /\ \> 詞尾定位符 /sh\>/ 匹配bash、csh、ksh、... ...

rootfs

模式的重復{}

x\{m\} x是字符或者字符串,m是數字,表示次數

匹配x出現m次 /a\{3\}/ 匹配到aaa

x\{m,\} 匹配x出現至少m次 /a\{3,\}/ 匹配aaa、aaaa、aaaaaaaa、aaaaaaa、... ...

x\{m,n\} 匹配x出現m次到n次 /a\{3,5\}/ 匹配aaa、aaaa、aaaaa

(root)

(a+(b-c)*d)

\(...\) 分組、標簽

& \1 \2

/\(love\)/ \1r

\(root\).*\(bin\).*\2\1 \1ly

a and b

\(a\) and \(b\) ==> \2 and \1

二.正則表達式用法

(一).vim與正則表達式

1、查找替換(letter) tom換成mary

~# vim letter

:%s/\<[Tt]om\>/mary/ ——> tom Tom

2、行首行尾 picnic

/^love

/love$

3、任意字符 picnic

/l.ve

4、前導符 picnic

/o*v

5、范圍 picnic

/love[a-z]

6、取反 picnic

/love[^a-z]

7、綜合 invite

/^[A-Z]..$ 匹配Dan這一行

/^[A-Z][a-z]*.*3[0-5] 匹配到There are around 30 to 35

//由此可以看出,正則表達式執行的是最大匹配

8、標簽

:%s/\(Ginger\) and \(Larry\)/\2 and \1/

:%s/\(Ginger\)\(.*\)\(Larry\)/\3\2\1/

s@@@ s### s%%% s/// 等價的

(二).grep與正則表達式

GREP —— Global Regular Expression Print

好處:非交互

不影響原文件內容,目的就是過濾出用戶感興趣的內容

命令格式

grep [選項] "正則表達式" 文件列表

grep執行狀態返回值三種

0:該文件中搜索到了匹配行

1:該文件中未搜索到匹配行

2: 搜索的文件不存在

~# grep "root" /etc/passwd

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

~# echo $?

0

~# grep "roooot" /etc/passwd

~# echo $?

1

~# grep "root" /etc/passwd1

grep: /etc/passwd1: No such file or directory

~# echo $?

2

grep基本使用

設定別名

#alias grep='grep --color=auto'

# vim /etc/bashrc

1、--color 帶顏色顯示匹配到的關鍵字

~# grep --color "root" /etc/passwd

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

2、-i 忽略大小寫

~# cat pass

Root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

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

~# grep "root" pass --color

Root:x:0:0:root:/root:/bin/bash

~# grep -i "root" pass --color

Root:x:0:0:root:/root:/bin/bash

3、-v 取反

~# grep -v "nologin" /etc/passwd //打印不包含nologin的行

4、^

打印/root/.bashrc文件中的注釋行

~# grep ^# /root/.bashrc

打印/etc/inittab文件中的非注釋行

~# grep -v ^# /etc/inittab

id:5:initdefault:

5、$

顯示passwd文件中以bash結尾的行

~# grep bash$ /etc/passwd

6、^$ 空行

~# grep -v ^$ /etc/rc.local

7、-c count 統計匹配到的行數

統計非空行的數量

~# grep -cv ^$ /etc/rc.local

7

統計空行的數量

~# grep -c ^$ /etc/rc.local

1

8、-r 遞歸檢索

9、-l 一般與-r聯用,只文顯示包含關鍵字的件名,而不是顯示文件內容

~# grep -rl "if" /script/

/script/adduser1.sh

/script/if7.sh

/script/for9.sh

/script/fuwu.sh

/script/if1.sh

10、-q quiet 靜默輸出 一般在寫腳本時候用

~# grep -q root /etc/passwd

~# echo $?

0

11、-n 顯示匹配行的行號

~# grep -n root /etc/passwd

1:root:x:0:0:root:/root:/bin/bash

11:operator:x:11:0:operator:/root:/sbin/nologin

其他選項

-A

-B

-C

練習:

1、顯示/etc/group文件中含有root的行

grep root /etc/group

2、顯示/etc/passwd中以rp開頭的行

grep ^rp /etc/passwd

3、顯示/etc/group中不以:結尾的行

grep -v :$ /etc/group

4、顯示/etc/rc.local的空行及其行號

grep -n ^$ /etc/rc.local

5、顯示僅/mnt/cdrom目錄下的文件類型為目錄的文件(不使用find)

ll /mnt/cdrom | grep ^d

grep 支持的正則元字符

^ $ . * [] [^] \< \> \{\} \(\)

~# vim example1.txt

asdf

ad

bsd

nsd

a.d

5.6

b.c

bcc

aff

~# grep a.d example1.txt

asdf

a.d

~# grep "a\.d" example1.txt

a.d

~# grep a*d example1.txt

asdf

ad

bsd

nsd

a.d

練習:/etc/passwd文件

1、匹配第2個字符是a的行

~# grep --color ^.a /etc/passwd

2、查找出/usr/bin目錄下具有suid權限的文件(不使用find)

~# ll /usr/bin/ | grep ^...[sS] --color

3、找出uid是兩位數的行

[0-9][0-9]

~# grep --color x:[0-9][0-9]: /etc/passwd

~# grep --color :[0-9][0-9]:[0-9] /etc/passwd

4、顯示passwd文件中含有兩個bin的行

bin.*bin

~# grep --color "bin.*bin" /etc/passwd

~# grep --color "\ bin:x:1:1:bin:/bin:/sbin/nologin

5、顯示passwd文件中含有三個root的行

~# grep "\(root\).*\1.*\1" /etc/passwd --color

root:x:0:0:root:/root:/bin/bash

6、顯示passwd文件中有9個連續的小寫字母的行

[a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z]

[a-z]\{9\}

~# grep "[a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z]" /etc/passwd --color

~# grep "[a-z]\{9\}" /etc/passwd --color

~# vim e2.txt

aabbcc

aaabbbccc

aaaannnmms

@@@##$

@@##@@

$$@#$%

1、找出e2.txt文件中含有三個連續的相同字符的行

~# grep "\(.\)\1\1" e2.txt --color

aaabbbccc

aaaannnmms

@@@##$

POSIX表示法

Portable Operating System Interface —— 可移植操作系統接口

也是適用於非英文環境的系統,即適用於所有的語言環境

括號類 含義 匹配范圍

[:space:] 包含換行符、空格、tab等所有空白字符

[:blank:] 空格和制表符 空格和tab

[:alpha:] 字母 a-zA-Z

[:alnum:] 字母和數字 a-Z0-9

[:cntrl:] 控制字符 ctrl、backspace等等

[:lower:] 小寫字母 a-z

[:upper:] 大寫字母 A-Z

[:digit:] 十進制數 0-9

[:xdigit:] 十六進制數 0-9a-fA-F

[:punct:] 標點符號 ,.?:' "

[^[:alpha:]] 取反,表示不是字母

~# grep "[[:space:]]\.[[:digit:]][[:space:]]" datafile --color

southwest SW Lewis Dalsass 2.7 .8 218

southeast SE Patricia Hemenway 4.0 .7 417

| 或者

? 表示0個或者1個它前面的字符 a?d ==> d ad

+ 表示1個或者多個它前面的字符 a+d ==> ad aad aaad ... ...

()

x{m}

x{m,}

x{m,n}

|

顯示datafile文件中含有NW或者是WE的行

~# egrep "NW|WE" datafile --color

~# grep -E "NW|WE" datafile --color

?

~# egrep "2\.?[0-9]" datafile --color

+

~# egrep "a+" e2.txt --color

aabbcc

aaabbbccc

aaaannnmms

三.sed

sed 流編輯器 stream editor

是一種非交互式文本編輯器,默認是不會修改原文件的

工作原理

一行一行處理的

從文件的第一行開始讀取,放到模式空間中進行相應處理,處理完將結果輸出到屏幕上,然後繼續讀取下一行,直到所有的行都處理完畢,sed結束。

sed一般用於處理大文件。

語法:

sed [選項] 'AddressCommand' 文件列表

1、常用的選項

-n:靜默輸出,關閉模式空間的輸出,一般與p一起用

-e:允許進行多項編輯,也就是說對同一行做多次處理、也可以做多點編輯

-e '動作' -e '動作' 等價於 '動作1;動作2'

-f sed腳本 : 指定運行的sed腳本的

-r:允許使用擴展正則

-i:直接修改原文件

2、Address : 定址、地址

1)單獨的行號

如: 1 就表示要處理第一行

$ 表示最後一行

2)起始行,結束行

如: 1,5 處理第一行到第五行

3)/正則表達式/

如:/^root/ 處理以root開頭的行

4)/正則表達式1/,/正則表達式2/ 最小匹配

表示處理從匹配到正則表達式1的行開始,到第一次匹配到正則表達式2之間的所有行

如果正則表達式1匹配到了,正則表達式2未匹配到,那麼就從匹配到正則表達式1的行開始,一直處理到文件結束

如果正則表達式1未匹配到,那麼就不對文件做處理。

如:/^bin/,/bash$/

binsdadaddaddass

dsfasidsfdhfj09bash

dasdasdasdf--bash

5)起始位置,+N 不是特別常用

表示從起始位置開始,後面的N行都處理

如:3,+5 處理3-8行

3、Command

常用的:d p s y q

其他的:a c i r w

h H g G

1)d:刪除

~# sed '/UUID/d' /etc/fstab

~# sed '1,5d' /etc/fstab

~# sed '$d' /etc/fstab

~# sed '/tmp/,/sfs/d' /etc/fstab

~# sed '/UUID/,+5d' /etc/fstab

刪除從第5行開始到最後一行的所有內容

~# sed '5,$d' /etc/passwd

2)p:打印

~# cat -n /etc/passwd | head > pass

~# sed 'p' pass //每行會打印兩遍,一遍是處理結果,一遍是模式空間的輸出

~# sed -n 'p' pass //只會打印一遍,因為模式空間的輸出被關閉了

~# sed -n '3,5p' pass // 打印文件的3到5行

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

~# sed -n '3p' pass

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

! 非

~# sed '3!d' pass //等價於打印第3行

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

練習:

用sed分別實現head -1 和 tail -1的功能

head -1

~# sed -n '1p' pass

1 root:x:0:0:root:/root:/bin/bash

~# sed '1!d' pass

1 root:x:0:0:root:/root:/bin/bash

tail -1

~# sed -n '$p' pass

10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

~# sed '$!d' pass

10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

3)r 讀取

~# sed '/^root/r /etc/issue' /etc/passwd

1 root:x:0:0:root:/root:/bin/bash

Red Hat Enterprise Linux Server release 6.4 (Santiago)

Kernel \r on an \m

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

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

9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

4)w 寫

~# sed '/root/w /tmp/douni' pass //將匹配到的行另存到文件中

~# cat /tmp/douni

1 root:x:0:0:root:/root:/bin/bash

5)a 追加 在匹配到的行的下一行插入內容

~# sed '/root/a hello root' pass | head -5

1 root:x:0:0:root:/root:/bin/bash

hello root

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

在文件的最後一行插入新內容

~# sed '$a The End' pass

1 root:x:0:0:root:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

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

9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

The End

6)i 插入 在匹配行的上一行插入內容

~# sed '/daemon/i SO COOL' pass | head -5

1 root:x:0:0:root:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

SO COOL

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

~# sed '1i BEGINNING' pass | head -5 //在第一行插入內容

BEGINNING

1 root:x:0:0:root:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

7)c 修改 本行替換,將匹配到的行的內容替換成新內容

~# sed '/root/c ROOT' pass

1 ROOT

ROOT:x:0:0:root

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

~# sed '/IPADDR/c IPADDR=172.16.254.201' /etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE=eth0

TYPE=Ethernet

ONBOOT=yes

NM_CONTROLLED=no

BOOTPROTO=static

IPADDR=172.16.254.201

NETMASK=255.255.0.0

GATEWAY=172.16.254.1

8)y 轉換的命令,對應替換

y///

y/123/ABC/

~# sed 'y/1234/ABCF/' pass

A root:x:0:0:root:/root:/bin/bash

B bin:x:A:A:bin:/bin:/sbin/nologin

C daemon:x:B:B:daemon:/sbin:/sbin/nologin

F adm:x:C:F:adm:/var/adm:/sbin/nologin

5 lp:x:F:7:lp:/var/spool/lpd:/sbin/nologin

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

9 mail:x:8:AB:mail:/var/spool/mail:/sbin/nologin

A0 uucp:x:A0:AF:uucp:/var/spool/uucp:/sbin/nologin

將文件中所有的小寫字母轉換成大寫字母

~# sed 'y/qwertyuiopasdfghjklzxcvbnm/QWERTYUIOPASDFGHJKLZXCVBNM/' pass

9)n next 處理匹配行的下一行,用的較少

~# sed -n '/root/p' pass

1 root:x:0:0:root:/root:/bin/bash

~# sed -n '/root/{n;p}' pass //{}裡面寫多個命令,之間用分號分隔

2 bin:x:1:1:bin:/bin:/sbin/nologin

10)q 退出 不再向模式空間讀入新行

~# sed '/^bin/q' /etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

~# sed '1q' pass //head -1的又一種方法

1 root:x:0:0:root:/root:/bin/bash

練習:

1、將pass文件每行打印3次

~# sed 'p;p' pass

2、打印passwd文件的第1行和第3行(多點編輯,用分號分隔命令)

~# sed -n '1p;3p' pass

1 root:x:0:0:root:/root:/bin/bash

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

~# sed -n -e '1p' -e '3p' pass

3、使用sed修改selinux的模式為permissive

~# sed '7c SELINUX=permissive' /etc/selinux/config

4、使用sed永久修改主機名為shell

~# sed '$c HOSTNAME=shell' /etc/sysconfig/network

3、刪除pass文件的第1行和最後一行

~# sed '1d;$d' pass

以下操作datafile文件

4、在匹配到Lewis的行的下一行插入“has Lewis”

~# sed '/Lewis/a has Lewis' datafile

5、在文件的第一行插入“employee's information”

~# sed "1i employee's information" datafile

11)s 查找替換

定址s/模式匹配(舊的內容)/新的內容/[修飾符]

s@@@ s### s%%%

修飾符:

g:全局替換,一行中的多個

n:n為數字,1-512 替換第n個匹配到的內容

p:打印

w:另存為,寫

~# sed 's/root/ROOT/' pass | head -3 //默認只替換第一次匹配到的

1 ROOT:x:0:0:root:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

~# sed 's/root/ROOT/2' pass | head -3 //替換每行中第2個匹配到的

1 root:x:0:0:ROOT:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

~# sed 's/root/ROOT/g' pass | head -3 //全部替換

1 ROOT:x:0:0:ROOT:/ROOT:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

練習:

1、從以root開頭,到以login結尾的行,將sbin替換成bin (/etc/passwd)

~# sed '/^root/,/login$/s/sbin/bin/' /etc/passwd | head

2、將格式為2015/09/02的日期,替換為2015; 09; 02的格式(注意分號後面有空格)

~# date "+%Y/%m/%d"

2015/09/02

~# date "+%Y/%m/%d" | sed 's#/#; #g'

2015; 09; 02

~# date "+%Y/%m/%d" | sed 's/\//; /g'

3、將selinux配置文件中的disabled替換為enforcing,暫時不作用於原文件

~# sed '/SELINUX/s/disabled/enforcing/' /etc/selinux/config

思考題:刪除文件中所有的數字 **** //一種思想,用替換去刪除字符等

~# sed 's/[0-9]//g' pass

-i:直接作用於文件

~# sed 's/static/dhcp/' /etc/sysconfig/network-scripts/ifcfg-eth0

~# sed -i 's/static/dhcp/' /etc/sysconfig/network-scripts/ifcfg-eth0

~# sed -i.bak 's/dhcp/static/' /etc/sysconfig/network-scripts/ifcfg-eth0

//.bak是備份文件的後綴名

~# ls /etc/sysconfig/network-scripts/ifcfg-eth0*

ifcfg-eth0 ifcfg-eth0.bak

模式匹配時的特殊符號

^:每行的開頭

給全文加注釋

~# sed 's/^/#/' pass

在第8到10行的開頭每行加上###

~# sed 's/^/###/' pass

$:每行的結尾

在匹配到root的行的末尾添加###

~# sed '/root/s/$/###/' pass

1 root:x:0:0:root:/root:/bin/bash###

-r選項: 支持擴展正則

~# sed -r 's/[[:space:]]+//' pass

~# sed 's/[[:space:]]*//' pass

1、將history命令執行結果中編號前面的空白字符刪掉

~# history | sed -r 's/[[:space:]]+//'

2、刪除文件中的空行和空白行

~# cat txt

adadadadada dasdasdadas

dadada

gdfgdgdfgfdg

~# cat -A txt

adadadadada dasdasdadas$

$

$

dadada $

^I^I $

gdfgdgdfgfdg$

~# sed -r '/^$/d;/^[[:space:]]+$/d' txt

adadadadada dasdasdadas

dadada

gdfgdgdfgfdg

& 引用 用來代替匹配到的模式的

將每一行的行號加上括號

~# sed -r 's/[0-9]+/(&)/' pass

~# vim test

hello, i like you

hi, my love

like ==> liker

love ==> lover

~# sed 's/l..e/l..er/' test

hello, i liker you

hi, my lover

~# sed -r 's/(l..e)/\1r/' test

hello, i liker you

hi, my lover

like ==> Like

love ==> Love

~# sed -r 's/l(..e)/L\1/' test

hello, i Like you

hi, my Love

練習:

1、刪除每行的第一個字符

2、刪除每行的第二個字符

3、刪除每行的倒數第一個字符

4、刪除每行的倒數第二個字符

5、交換每行的第一個和第二個字符

思考:

刪除/etc/passwd每行的第一個字段

交換/etc/passwd文件的第一個和第二個字段

作業:

1、將/etc/inittab文件中的id:5:initdefault中的5替換成3

以下使用datafile3

1、將Jon的名字改為Jonathan

2、刪除文件的前3行

3、打印文件的第5到10行

4、刪除含有Lane的行

5、打印生日在11月和12月的行

6、在以Fred開頭的行末尾添加三個*

7、將所有包含Jose的行替換為Match Jose

8、把Popeye的生日改為11/14/46,前提:需要你先匹配出生日

9、刪除所有的行

10、將文件中的所有大寫字母用括號()括起來

每多少行操作一次

first~step

first:起始行號

step:步長

打印偶數行

~# sed -n '2~2p' pass

2 bin:x:1:1:bin:/bin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

6 sync:x:5:0:sync:/sbin:/bin/sync

8 halt:x:7:0:halt:/sbin:/sbin/halt

10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

每3行打印一次

~# sed -n '1~3p' pass

1 root:x:0:0:root:/root:/bin/bash

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

=:打印當前行號

統計文件的行數

~# sed -n '$=' /etc/passwd

76

~# vim sc1.sed

/Lewis/a \

hello everyone \

ni hao

/Suan/c has suan

1i \

************** \

begin \

**************

$d

調用腳本

~# sed -f sc1.sed datafile

**************

begin

**************

northwest NW Charles Main 3.0 .98 334

western WE Sharon Gray 5.3 .97 5 23

southwest SW Lewis Dalsass 2.7 .8 218

hello everyone

ni hao

has suan

southeast SE Patricia Hemenway 4.0 .7 417

eastern EA TB Savage 4.4 .84 520

northeast NE AM Main Jr. 5.1 .94 313

western WE Sharon Gray 5.3 .97 5 23

north NO Margot Weber 4.5 .89 59

模式空間

用於處理文本行的

PATT,最多能夠存儲8192字節

保留空間

用於保留文本行的

HOLD,sed用來保存已經處理過的文本行的,最多保存8192字節,默認有一個空行

涉及到的命令

h:將模式空間的內容復制到保留空間 —— 覆蓋模式

H:將模式空間的內容追加到保留空間 —— 追加模式

g:將保留空間的內容復制到模式空間 —— 覆蓋模式

G:將保留空間的內容追加到模式空間 —— 追加模式

x:將模式空間的內容和保留空間的內容進行交換

交換第一行和第二行的內容

~# sed '1{h;d};2G' pass | head -5

2 bin:x:1:1:bin:/bin:/sbin/nologin

1 root:x:0:0:root:/root:/bin/bash

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

將第1行到第3行的內容復制到第4行後面

~# sed '1h;2,3H;4G' pass | head

1 root:x:0:0:root:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

1 root:x:0:0:root:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

6 sync:x:5:0:sync:/sbin:/bin/sync

7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

將第1行到第3行的內容剪切到第4行的後面

~# sed '1{h;d};2,3{H;d};4G' pass

4 adm:x:3:4:adm:/var/adm:/sbin/nologin

1 root:x:0:0:root:/root:/bin/bash

2 bin:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

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

9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

在每行的下面添加一個空行

~# sed 'G' pass

思考:倒序輸出文件的每一行

假設文件如下:

aa

bb

cc

dd

要求輸出結果如下:

dd

cc

bb

aa

四.awk

awk 一種編程語言、文本編輯器、也是一種非交互式的編輯器

功能:對文本數據進行匯總和處理,是一個報告的生成器,能夠對數據進行排版

awk nawk gawk posix awk

nawk —— solaris

gawk,awk —— GNU Linux

工作過程

將文件中的內容逐行的進行掃描,把整行內容存入內置變量$0中;

再按照指定的分隔符(默認的分隔符是空白)將輸入行切成若干個列(字段),存入變量$1~$100,再使用命令(print、printf)將變量打印輸出,輸出分隔符默認也是空白

再讀取下一行,循環處理,直到文件處理結束。

~# ifconfig eth0 | grep Bcast | awk '{print $2}' | awk -F: '{print $2}'

172.16.254.200

~# df -h / | tail -1 | awk '{print $5}' | cut -d"%" -f1

18

1、awk的語法

awk [選項] '/模式匹配(定址)/{處理動作1;處理動作2;... ...; 處理動作n}' 文件列表

2、簡單操作

~# head /etc/passwd > pass

打印pass文件中的用戶名和uid

~# awk -F: '{print $1,$3}' pass

-F:指定輸入文件字段分隔符

3、語法中的說明

1)設定輸入分隔符 -F

分隔符可以是數字、字母、符號和空白

可以同時指定多個分隔符 : / ,

默認是空白

---- 單個符號的分隔符

-F:

---- 復合分隔符,多個字符組成一個分隔符

:/

pass文件以:/為分隔符,打印第一個字段

~# awk -F":/" '{print $1}' pass

---- 同時指定多個分隔符

:和/都是分隔符

~# awk -F"[:/]" '{print $1,$10}' pass

---- 以空為分隔符

~# awk -F "" '{print $1,$2}' pass //注意:-F後面有空格

2)awk輸出

(1)print

打印內容的,內容可以是文件中的內容,也可以跟文件內容毫無關系

~# awk '{print "hello"}' pass //打印內容和文件不相關,只是借用了pass文件的行,有多少行內容,hello就會被打印多少次

打印每一行的內容

~# awk '{print $0}' pass

~# awk '{print}' pass

\n :換行符

~# head -1 pass | awk '{print "hello\nworld"}'

hello

world

\t : 制表符

~# head -1 pass | awk '{print "hello\tworld"}'

hello world

~# awk -F: '{print $1"\t"$3}' pass

print要點:

a、各個輸出字段之間用逗號分隔,而輸出的時候默認是以空白為分隔符的

b、print後面如果不跟字段,那麼默認打印整行

c、print輸出時默認是有換行的

1、在每行的下面打印一個空行

~# awk '{print $0"\n"}' pass

2、使用awk取出eth0網卡的IP地址

~# ifconfig eth0 | awk '/Bcast/{print $2}' | cut -d: -f2

172.16.254.200

(2)printf —— 可以格式化輸出的,默認沒有換行

使用格式

printf format,item1,item2,... ...,itemn

format的指示符都是以%開頭的,後面跟一個字符,如:

%s:表示是字符串

%d:表示十進制數

%f: 表示浮點數,其實就是小數 float

%%:表示%本身

%x:表示十六進制數

%o:表示八進制數

%c:表示字符

修飾符: N(數字) 表示顯示寬度 %10s

- 表示左對齊,默認是右對齊 %-10s

對於浮點數:

%5.2f : 其中5表示總的顯示寬度(整數位+小數位),2表示小數位的位數

%-5.2f

%.2f :表示整數位全部保留,小數位保留兩位

~# awk -F : '{printf "%10s%5d",$1,$3}' pass //默認printf是沒有換行的

root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 uucp 10~#

~# awk -F : '{printf "%10s%5d\n",$1,$3}' pass

~# awk -F : '{printf "%-10s%5d\n",$1,$3}' pass

%d直接取整,不進行四捨五入;%f進行四捨五入的

~# echo "12.64 23.456 11.2345" > test

~# awk '{printf "%d\n",$1}' test

12

~# awk '{printf "%.2f\n",$2}' test

23.46

printf要點:

a、與print不同的是,printf需要指定格式

b、格式其實是用來指定後面每個條目的輸出格式的

c、printf默認不會自動打印換行符的,有需要時候手動指定"\n"

d、默認沒有輸出分隔符

~# awk '{printf "%d%d\n",$1,$2}' test

1223

~# awk '{printf "%d %d\n",$1,$2}' test

12 23

練習:

格式化輸出passwd文件中的用戶名,UID,shell三列

~# awk -F: '{printf "%-15s%-6d%-15s\n",$1,$3,$7}' /etc/passwd

3)awk的操作符

(1)算數運算符

-x:表示負數 +x(x):表示正數

x+y x-y x*y x/y x%y x**y 等價於 x^y(x的y次冪)

~# awk '{print $3+$5}' employees

547778

34111

651654

338183

~# awk '{print $3+$5,$3-$5,$3*$5,$5/$3,$5%$3}' employees

547778 -538930 2403798096 122.82 3626

34111 -23419 153777690 5.38066 2035

651654 -648346 1075100000 392.987 1632

338183 -334817 566329500 199.941 1583

~# echo hello | awk '{print 2^16}'

65536

~# awk '{printf "%-10d\n",$5+$3}' employees

547778

34111

651654

338183

(2)關系運算符

a、數值之間的關系運算符

> < >= <= == !=

打印uid小於等於10 的行

~# awk -F: '$3<=10{print $0}' /etc/passwd

~# awk -F: '$3<=10{print}' /etc/passwd

~# awk -F: '$3<=10' /etc/passwd

b、字符串之間的關系運算符

== !=

$1=="root"

$1!="root"

~# awk -F: '$1=="root"' pass

root:x:0:0:root:/root:/bin/bash

x ~ /y/ —— 匹配正則 其中y可以是正則表達式

打印用戶名中含有o的用戶的名字

~# awk -F: '$1 ~ /o/{print $1}' pass

root

daemon

shutdown

x !~ /y/ —— 不匹配正則

~# awk -F: '$1 !~ /o/{print $1}' pass

bin

adm

lp

sync

halt

mail

uucp

練習:

1、打印/etc/fstab中含有boot的行

~# awk '/boot/' /etc/fstab

~# awk '$0 ~ /boot/' /etc/fstab

2、打印/etc/passwd文件中的uid為10的用戶的用戶名、uid及家目錄

~# awk -F: '$3==10{print $1,$3,$6}' /etc/passwd

uucp 10 /var/spool/uucp

3、打印用戶shell為登錄shell的用戶名及shell

~# awk -F: '$7 ~ /sh$/{print $1,$7}' pass

root /bin/bash

(3)邏輯運算符

&&  ||   !

打印uid在5到10之間的用戶的用戶名,UID

~# awk -F: '$3>=5 && $3<=10{print $1,$3}' /etc/passwd

sync 5

shutdown 6

halt 7

mail 8

uucp 10

打印uid大於10或者uid小於5的用戶名

~# awk -F: '$3<5 || $3>10{print $1,$3}' /etc/passwd

打印uid不大於3的用戶名

~# awk -F: '!($3>3){print $1,$3}' pass

(4)賦值運算符

= += -= *= /= %= **= ^=

++ --

sum+=$3

練習:

1、打印uid和gid不相同的用戶的用戶名、uid、gid

~# awk -F: '$3!=$4{print $1,$3,$4}' /etc/passwd

2、交換pass文件的第一個字段和第二個字段

~# awk -F: '{print $2":"$1":"$3":"$4":"$5":"$6":"$7}' pass

3、打印100以內能夠被7整除,以及包含7 的數

~# seq 100 | awk '$0%7==0 || $0 ~ /7/'

~# seq 100 | awk '$0%7==0 || /7/'

4、awk的模式匹配(即定址) —— awk + 正則表達式

常見的模式

1)空模式:也就是每一行都要做處理的模式

~# awk -F: '{print $1}' pass

2)正則表達式

a、固定定址

~# awk -F: '/^ro/{print $1}' pass

root

b、范圍定址

~# awk -F: '/^ro/,/^lp/{print $1}' pass

root

bin

daemon

adm

lp

注意:awk是不支持行號定址的

反例:

~# awk -F: '2{print $1}' pass

3)表達式

$3>=5

$7 ~ /sh$/

4)特殊模式

BEGIN {}

END {}

5)NR變量定址

NR>1 //行號大於1的行

5、awk的變量

種類:內置變量、自定義的變量

1)內置變量

(1)$0 表示一整行的內容

(2)$1 ~ $100

$1:第一列

(3)與記錄相關的變量(記錄就是行)

FS(field separator):字段分隔符,默認是空白

FS=":"

OFS(Output):輸出字段分隔符

RS(record):記錄的分隔符,即行的分隔符

ORS:輸出記錄分隔符

(4)與數據相關的變量

NR(Number of Record):記錄數,awk的處理的行的總數 NR在很多情況下可以看成行號

NF(Number of Field):當前行的字段數

$NF:當前行的最後一個字段的值

$(NF-1):當前行的倒數第二個字段

~# cat employees

Tom Tom 4424 5/12/66 543354

Mary Adams 5346 11/4/63 28765

Sally Chang 1654 7/22/54 650000

Billy Black 1683 9/23/44 336500

Tom Tom 4424 5/12/66

~# awk '{print NR":"NF":"$NF}' employees

1:5:543354

2:5:28765

3:5:650000

4:5:336500

5:4:5/12/66

打印pass文件的第2行

~# awk 'NR==2' pass

bin:x:1:1:bin:/bin:/sbin/nologin

2)自定義變量

命名:由字母、數字、下劃線組成,不能以數字開頭,不能使用關鍵字,最好見名知意

變量名區分大小寫

變量可以先定義再使用,也可以直接使用

給變量賦值

變量名=數值

a=5

變量名="字符串" //注意:此處一定有引號

username="root"

~# echo hello | awk '{num=5;pass="douniwan";print num,pass}'

5 douniwan

練習:

1、打印passwd文件的奇數行的行號和內容

NR%2==1 或者 NR%2!=0

2、打印每行的倒數第三個字段(employees文件)

$(NF-2)

3、從第一行開始,每3行打印一次(即打印行號為1 4 7... 這樣的行)

NR%3==1

4、輸出以 : 和 / 為分隔符的情況下,passwd文件的最後一列

-F"[:/]" $NF

5、打印/etc/passwd文件的偶數行

NR%2==0

6、打印pass文件中沒有指定shell的用戶名(文件自己處理一下,可以將某個或者某幾個的shell刪除掉)

-F: $7 == ""

$7 ~ /^$/

7、打印passwd文件的第3行和第5行

NR==3 || NR==5

sed相關練習

1、將passwd文件 中的第20行到第30行的內容復制到第33行後面,同時顯示行號(可以使用除了sed以外的命令)

cat -n passwd | sed '20h;21,30H;33G'

2、寫sed腳本 處理文件為datafile3

1)在第一行插入標題:EMPLOYEES

2)刪除以500為結尾的行的工資項(注意:不是刪除行,只是刪除工資那個段)

3)將名和姓的位置顛倒輸出

4)在文件末尾添加OVER

1i EMPLOYEES

s/:[0-9]*500$/:/

s/^([A-Z][a-z]*) ([A-Z][a-z]*)/\2 \1/

$a OVER

sed -rf script.sed datafile3

--------------------------------------------------------------------------------------

6、賦值運算

a+=$2 等價於 a=a+$2

a+=5

-= *= /= %= ^=

a++ ++a

a-- --a

~# echo hello | awk '{a=5;b=a++;print a,b}'

6 5

~# echo hello | awk '{a=5;b=++a;print a,b}'

6 6

練習:

1)把employees裡面最後一個字段的值減去8,打印

~# awk '{print $NF-8}' employees

543346

28757

649992

336492

2)將employees倒數第三列對3取余並打印

~# awk '{print $(NF-2)%3}' employees

2

0

1

0

0

~# awk '{a=$(NF-2)%3;print a}' employees

2

0

1

0

0

7、awk的特殊模式

awk的完整語法

awk [選項] 'BEGIN{動作}定址{動作}END{動作}' 文件列表

BEGIN{} : 在讀取文件之前就執行,只執行一次;一般用於初始化分隔符、初始化變量、定義數組、打印表頭等

定址{} : 這一部分可能會執行多次

END{} : 在處理完文本之後執行,只執行一次;一般用於匯總數據 比如:打印總成績、平均成績等等

~# awk 'BEGIN{FS=":";print "username"}/root/{print $1}END{print "over"}' /etc/passwd

username

root

operator

over

說明:

BEGIN和END可以單獨存在的

1)只有BEGIN,後面不需要加文件

~# awk 'BEGIN{print "hello"}'

hello

2)只有END,後面必須加文件,文件可以是空文件,也可以是有內容的文件

~# awk 'END{print "end"}' pass

end

~# touch haha

~# awk 'END{print "end"}' haha

end

3)沒有BEGIN,也沒有END

~# awk '{sum=0;sum+=$3;print $1,$3,sum}' employees

Tom 4424 4424

Mary 5346 5346

Sally 1654 1654

Billy 1683 1683

Tom 4424 4424

4)有BEGIN,沒有END‘

~# awk 'BEGIN{sum=0}{sum+=$3;print $1,$3,sum}' employees

Tom 4424 4424

Mary 5346 9770

Sally 1654 11424

Billy 1683 13107

Tom 4424 17531

5)既有BEGIN,又有END

~# awk 'BEGIN{sum=0}{sum+=$3;print $1,$3}END{print "total:"sum}' employees

Tom 4424

Mary 5346

Sally 1654

Billy 1683

Tom 4424

total:17531

練習:

統計/etc目錄下所有的普通文件的總大小

~# ll /etc | awk 'BEGIN{sum=0}/^-/{sum+=$5}END{print sum}'

1257642

8、awk的腳本

BEGIN{

命令

}

定址{

命令

}

END{

命令

}

打印ule總成績,平均成績

~# vim sc.awk

BEGIN{

print "This is ule score table"

}

NR>1{

ule+=$2

}

END{

print "ule's total score is :"ule

print "ule's average score is :"ule/(NR-1)

}

~# awk -f sc.awk score

This is ule score table

ule's total score is :246

ule's average score is :61.5

練習:

1、求得ULA的總成績,平均成績;求oracle的總成績,平均成績

2、樣例文件staff.txt

文件內容如下:

~# cat staff.txt

id name sal date

100 tom 10000 2013/10/1

101 jerry 8000 2013/10/10

102 john 5000 2013/11/1

103 mark 6000 2013/12/10

104 rose 2000 2014/01/01

105 jake 1500 2014/01/10

1)統計每個月發出去的總工資

~# awk 'NR>1{sal+=$3}END{print sal}' staff.txt

32500

NR>1{

sal+=$3

}

END{

print sal

}

2)統計2013年入職的人數

~# awk '/2013/{count++}END{print count}' staff.txt

4

3)統計工資超過5000的有幾個人

~# awk '$3>5000 && NR>1 {count++}END{print count}' staff.txt

3

1、awk與重定向

passwd

將uid>100的用戶名及uid保存到/tmp/uidup100文件中

~# awk -F: '$3 > 100{print $1,$3 > "/tmp/uidup100"}' /etc/passwd

輸入重定向 getline

getline 接收來自於標准輸入、管道和文件(非當前處理文件)的數據,存入到一個變量中,再給awk使用

~# awk 'BEGIN{"date" | getline a}{print $0}END{print a}' pass

~# tty

/dev/pts/10

從標准輸入讀取一個數據,傳給變量username,判斷passwd文件中是否有這樣的用戶名,如果有,打印行號和用戶名

~# vim sc2.awk

BEGIN{

FS=":"

printf "請輸入一個用戶名: "

getline username < "/dev/pts/10"

}

{

if($1==username) 判斷

{

print NR,$1

}

}

~# awk -f sc2.awk /etc/passwd

請輸入一個用戶名: root

1 root

2、awk與管道

~# awk -F: '$3 > 100{print $1,$3 | "sort -nr -k2"}' /etc/passwd

3、使用awk執行系統命令

~# awk 'BEGIN{print "today is ";system("date")}'

today is

Mon Sep 7 12:26:03 CST 2015

基本的結構

1、順序結構

2、分支判斷 if

3、循環結構 while for 循環控制語句:break continue exit next

一、三元操作符

?:

判斷條件?輸出結果1:輸出結果2

如果條件為真,輸出問號後面的結果,否則輸出冒號後面的結果

~# awk -F: '{print $1":"($3>$4?"uid:"$3:"gid:"$4)}' pass

二、分支判斷結構 if

1、語法格式:

if(條件表達式) —— 注意:如果if是寫在awk的腳本中,那麼他的整體都要寫在{}中,因為它屬於動作

{

動作

}

else

{

動作

}

修改三元操作符的小練習

~# vim if1.awk

BEGIN{

FS=":"

}

{

if($3>$4)

{

print $1":uid:"$3

}

else

{

print $1":gid:"$4

}

}

~# awk -f if1.awk pass

2、多分支判斷語法結構

if(條件表達式)

{

動作

}

else if(條件表達式)

{

動作

}

... ...

else

{

動作

}

~# cat if2.awk

#!/usr/bin/awk -f //shabang,指定文件中的命令的解析環境是awk

NR>1{

if($2>=90)

{

print $1": A"

}

else if($2>=80)

{

print $1": B"

}

else

{

print $1": C"

}

}

~# chmod +x if2.awk

~# ./if2.awk score

mike: B

rose: C

john: A

larry: C

練習:

統計ula成績在以下每個分數段的人數

>=90

>=80

>=70

打印效果:

成績在90分以上的有__人

成績在80分到90分之間的有__人

成績在70分到80分之間的有__人

~# cat if3.awk

#!/usr/bin/awk -f

NR>1{

if($3>=90)

{

up90++

}

else if ($3>=80)

{

up80++

}

else if($3>=70)

{

up70++

}

}

END{

printf "成績在90分以上的有%d人\n",up90

printf "成績在80分到90分之間的有%d人\n",up80

printf "成績在70分到80分之間的有%d人\n",up70

}

~# chmod +x if3.awk ^C

~# ./if3.awk score

成績在90分以上的有1人

成績在80分到90分之間的有1人

成績在70分到80分之間的有1人

三、循環

功能:

1)從行中取出每個字段,循環字段的

2)遍歷數組元素

1、while循環

語法:

變量初始值

while (條件)

{

動作

變量的更新

}

mike

85

80

90

~# vim while1.awk

/mike/{

i=1

while(i<=NF)

{

print $i

i++

}

}

~# awk -f while1.awk score

mike

85

80

90

練習:

1)將passwd文件的第一行的每個字段縱向打印

輸出結果如下:

root

x

0

0

root

/root

/bin/bash

~# cat while2.awk

BEGIN{

FS=":"

}

NR==1{

i=1

while(i<=NF)

{

print $i

i++

}

}

2)倒序輸出passwd文件的每一列

結果例如(以一行為例)

/bin/bash:/root:root:0:0:x:root

法一:

~# awk 'BEGIN{FS=":";OFS=":"}{print $7,$6,$5,$4,$3,$2,$1}' pass

法二:

~# cat while4.awk

BEGIN{

FS=":"

}

{

i=NF

while(i>1)

{

printf $i":"

i--

}

print $1

}

2、for循環

語法:

for(變量初始值;判斷條件;變量的更新)

{

動作

}

~# vim for1.awk

/mike/{

for(i=1;i<=NF;i++)

{

print $i

}

}

四、判斷加循環

~# awk 'NR>1{print $2,$3,$4}' score > number

例子:

輸出每行的最大值

~# vim if-for.awk

{

max=$1

for (i=1;i<=NF;i++)

{

if($i>max)

{

max=$i

}

}

print max

}

~# awk -f if-for.awk number

90

70

91

100

五、雙重循環 (嵌套循環)

打印99乘法口訣表

~# vim for-for.awk

BEGIN{

for(i=1;i<=9;i++)

{

for(j=1;j<=i;j++)

{

printf j"*"i"="i*j"\t"

}

printf "\n"

}

}

~# awk -f for-for.awk

1*1=1

1*2=2 2*2=4

1*3=3 2*3=6 3*3=9

1*4=4 2*4=8 3*4=12 4*4=16

1*5=5 2*5=10 3*5=15 4*5=20 5*5=25

1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36

1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49

1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64

1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81

六、循環控制語句

continue 跳出本次循環

~# cat for-for.awk

BEGIN{

for(i=1;i<=9;i++)

{

for(j=1;j<=i;j++)

{

if (j==4) {continue}

else

{

printf j"*"i"="i*j"\t"

}

}

printf "\n"

}

}

break 跳出當前循環

~# cat for-for.awk

BEGIN{

for(i=1;i<=9;i++)

{

for(j=1;j<=i;j++)

{

if (j==4) {break}

else

{

printf j"*"i"="i*j"\t"

}

}

printf "\n"

}

}

exit 退出腳本

~# cat for-for.awk

BEGIN{

for(i=1;i<=9;i++)

{

for(j=1;j<=i;j++)

{

if (j==4) {exit}

else

{

printf j"*"i"="i*j"\t"

}

}

printf "\n"

}

}

next 跳過本行,讀取下一行

~# awk '/name/{next};{print $0}' score

數組: array

數組是使用一個變量名 來保存一組數據,通常這些數據的類型是一樣的

數組中的數據(元素) 是與數組下標一一對應的

如果想要取出數組中的某個元素,就會使用到數組名和下標

awk中的數組也成為關聯數組,是因為它的下標可以是數值,也可以是字符串

一、數組的定義

數組名[下標]=值

二、數組的遍歷

for循環遍歷數組

語法:

1)for (i=0;i 2) for (下標 in 數組名) {print 數組名[下標]}

定義數組及給數組中元素賦值

~# vim arr.awk

BEGIN{

a[1]="aa"

a[2]="bb"

a[3]="cc"

for(i=1;i<=3;i++)

{

print a[i]

}

}

~# awk -f arr.awk

aa

bb

cc

awk支持的下標的類型

1)使用數字或變量作為下標

name[1] name[x++] name[NR]

~# awk '{name[x++]=$1}END{for(i=0;i 0 Tom

1 Mary

2 Sally

3 Billy

4 Tom

2)使用字符串做下標

name["tom"]++

~# vim datafile4

cat

dog

pig

cat

dog

dog

bird

dog

rabbit

統計文件中每種動物有幾只?

~# awk '{count[$1]++}END{for(i in count){print i,count[i]}}' datafile4

cat 2

bird 1

rabbit 1

dog 4

pig 1

統計apache日志中每個IP的訪問次數,顯示訪問次數最多的五個IP及訪問次數

統計/root/.bash_history文件中執行次數最多的十條命令

統計系統中使用每種shell的有幾個人?

統計服務器上tcp連接情況(每種監聽狀態有幾個?)

如:

LISTEN 10

ESTABLISHED 30

~# netstat -ant

內置函數

自定義函數

一、內置函數

man awk //搜索Function

1、sub(正則表達式,替換字符串) —— 查找並替換

~# awk '{sub(/NW/,"NorthWest");print}' datafile

northwest NorthWest Charles Main 3.0 .98 3 34

2、tolower(字符串) —— 轉換成小寫

toupper(字符串) —— 轉換成大寫

~# awk '{print toupper($1)}' datafile

~# awk '{print tolower($2)}' datafile

3、index(原字符串,子串) —— 輸出子串在原字符串中的位置

~# awk '{print index($1,"o"),$1}' datafile

2 northwest

0 western

2 southwest

2 southern

2 southeast

0 eastern

2 northeast

0 western

2 north

0 central

4、length(字符串) —— 顯示字符串的長度

~# awk '{print length($1),$1}' datafile

9 northwest

7 western

9 southwest

8 southern

9 southeast

7 eastern

9 northeast

7 western

5 north

7 central

二、自定義函數

格式

function 函數名(參數1,參數2,... ... ,參數n) {

函數體

return value //返回值

} //參數也是可有可無的

~# awk 'function hello(){print "shell is over"}{hello()}' pass

Copyright © Linux教程網 All Rights Reserved