awk sed 总结

Awk总结笔记

 

 

 

 

介绍

 

90年代 new awk :nawk

Linux 的是gawk 我们简化awk

 

 

用法

 

#  awk [options ] ‘scripts’ file1 file2 ....

# awk [options ] ‘PATTERN {action }’ file1 file2 ....

 

读入文本先切片如下 切5片

每片$n  整行$0

 

 

每行片数不一样

Print

 

内置变量

    以下为awk内置变量:

          ARGC        命令行参数个数

          FILENAME    当前输入文档的名称

          FNR        当前输入文档的当前记录编号,尤其当有多个输入文档时有用

          NR        输入流的当前记录编号

          NF        当前记录的字段个数

          FS        字段分隔符

          OFS        输出字段分隔符,默认为空格

          ORS        输出记录分隔符,默认为换行符\n

          RS        输入记录分隔符,默认为换行符\n

    示例:

 

显示第一列字段  第一片

[root@centos5 awk]# cat a.txt 

welcome to my heart

i am liujianzuo 

how are u?

 

[root@centos5 awk]# awk '{print $1}' a.txt 

welcome

i

How

 

[root@centos5 awk]# df -hP  #显示到一行

Filesystem            Size  Used Avail Use% Mounted on

/dev/sda3             7.1G  3.2G  3.6G  48% /

/dev/sda1             198M   13M  176M   7% /boot

tmpfs                  63M     0   63M   0% /dev/shm

/dev/sdb1              99M  6.1M   88M   7% /data

[root@centos5 awk]# df -h|awk '{print $1}'       

Filesystem

/dev/sda3

/dev/sda1

tmpfs

/dev/sdb1

 

-F 指定分隔符

类似cut -d

[root@centos5 awk]# awk -F : '{print $1}' /etc/passwd 

root

bin

daemon

adm

lp

sync

shutdown

halt

mail

news

uucp

operator

games

gopher

ftp

nobody

nscd

vcsa

pcap

ntp

dbus

如果你的列数不一致 怎么取左后一列 $NF

 

 

[root@centos5 awk]# awk -F : '{print $NF}' /etc/passwd 

/bin/bash

/sbin/nologin

/sbin/nologin

/sbin/nologin

/sbin/nologin

/bin/sync

/sbin/shutdown

/sbin/halt

/sbin/nologin

 

/sbin/nologin

/sbin/nologin

/sbin/nologin

 

打印倒数第2字段 将NF做数学运算

[root@centos5 awk]# cat a.txt 

welcome to my heart

i am liujianzuo 

how are u?

[root@centos5 awk]# awk '{print $(NF-2)}' a.txt  

to

i

how

 

-F 改变分隔符 FS字段分隔符读入的时候也能实现

[root@centos5 awk]# awk -v FS=: '{print $NF}' /etc/passwd|tail -3   

/sbin/nologin

/bin/bash

/bin/bash

 

输出的分隔符 OFS 默认是逗号分开变量,输出空格的

[root@centos5 awk]# awk '{print $1 $2}' a.txt                       

welcometo

iam

howare

[root@centos5 awk]# awk '{print $1,$2}' a.txt  

welcome to

i am

how are

[root@centos5 awk]# awk -v OFS=: '{print $1,$2}' a.txt   

welcome:to

i:am

how:are

Printf

 

字符串个数%s 双引号引起来

不会自动换行 需要\n

格式符候还可以加修饰符

如下是每一行开始第一列字段是10个字符对其,第二列字段是1个字符对其,默认右对齐

,不会自动换行

[root@centos5 awk]# awk '{printf "%10s,%s",$1,$2}' a.txt  

   welcome,to         i,am       how,are[root@centos5 awk]# 

让其换行\n

[root@centos5 awk]# awk '{printf "%10s,%s\n",$1,$2}' a.txt 

   welcome,to

         i,am

       how,are

输出左对齐 修饰符 -

[root@centos5 awk]# awk '{printf "%-10s,%-s\n",$1,$2}' a.txt 

welcome   ,to

i         ,am

how       ,are

 

格式之间的符号会输出,不需要写

[root@centos5 awk]# awk '{printf "%-10s%-s\n",$1,$2}' a.txt  

welcome   to

i         am

how       are

 

print输出重定向

 

 

 

 

将print 打印结果输出

[root@centos5 awk]# awk -F : '{printf "%-10s %i\n",$1,$3 > "/dev/stderr" }' /etc/passwd   #改变输出流,引号引起来

[root@centos5 awk]# awk -F : '{printf "%-10s %i\n",$1,$3 > "/server/scripts/awk/passwd.log" }' /etc/passwd     #改变输出流          

[root@centos5 awk]# cat passwd.log  

root       0

bin        1

daemon     2

adm        3

lp         4

sync       5

shutdown   6

halt       7

mail       8

news       9

uucp       10

operator   11

games      12

gopher     13

ftp        14

nobody     99

nscd       28

vcsa       69

pcap       77

ntp        38

dbus       81

avahi      70

rpc        32

mailnull   47

smmsp      51

oprofile   16

sshd       74

rpcuser    29

nfsnobody  65534

xfs        43

haldaemon  68

avahi-autoipd 100

oldboy     500

mysql      501

nginx      502

nagios     503

disdata    999

ayibang    1000

 

Awk的操作符

 

 

正则匹配=应该用[=]

 

 

 

 

这里y是种模式

 

 

第三个字符串操作符实例

[root@centos5 awk]# awk 'BEGIN{print "a" "b"}'        

ab

第五个模式匹配

匹配某一行第一个字段是以root开头的模式我们就打印第3 4 最后一个字段

[root@centos5 awk]# awk -F : '$1 ~ /^root/ {print $3,$4,$NF}' /etc/passwd

0 0 /bin/bash

 

Awk的模式

 

 

 

 

 

 

正则表达式 模式+动作

awk正则表达式使用外部变量

 

awk的正则表达式匹配中,如果要使用外部shell
变量,先在变量外加双引号,再加单引号即可,如:

for i in read write print; 

do 

cat file.txt | awk '{ if ($7~/'"$i"'/) {print $0} }'| wc -l ; 

done

 

匹配pation之后是动作如下例子,匹配bash这个模式后动作是打印匹配的包含的全部

# awk [options ] 'PATTERN {action }' file1 file2 ....

 

[root@centos5 awk]# awk -F : '/bash/ {print $0}' /etc/passwd        root:x:0:0:root:/root:/bin/bash

oldboy:x:500:500::/home/oldboy:/bin/bash

disdata:x:999:999::/home/disdata:/bin/bash

ayibang:x:1000:1000::/home/ayibang:/bin/bash

[root@centos5 awk]# awk -F : '/bash/ {print $1}' /etc/passwd 

root

oldboy

disdata

ayibang

表达式

 

 

[root@centos5 awk]# awk -F : '$3 >= 500 {print $1}' /etc/passwd     

nfsnobody

oldboy

mysql

nginx

nagios

disdata

ayibang

[root@centos5 awk]# awk -F : '$3 >= 500 {print $1,$3}' /etc/passwd

nfsnobody 65534

oldboy 500

mysql 501

nginx 502

nagios 503

disdata 999

ayibang 1000

 

匹配指定范围 的模式

/bash/,/500/

[root@centos5 ceshi]# awk '/bash|500/ {print $0}' /etc/passwd

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

oldboy:x:500:500::/home/oldboy:/bin/bash

disdata:x:999:999::/home/disdata:/bin/bash

ayibang:x:1000:1000::/home/ayibang:/bin/bash

liujianzuo:x:1001:1001::/home/liujianzuo:/bin/bash

Begin end 特殊模式

[root@centos5 ~]# awk -F: '$3>=500 {print "USERNAME       UID";printf "%-15s%s\n",$1,$3}' /etc/passwd    #在awk预读每一行的时候,都打印一行

USERNAME       UID

nfsnobody      65534

USERNAME       UID

oldboy         500

USERNAME       UID

mysql          501

USERNAME       UID

nginx          502

USERNAME       UID

nagios         503

USERNAME       UID

disdata        999

USERNAME       UID

ayibang        1000

[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"} $3 >= 500 {printf "%-15s%s\n",$1,$3}' /etc/passwd 

USERNAME       UID

nfsnobody      65534

oldboy         500

mysql          501

nginx          502

nagios         503

disdata        999

ayibang        1000

liujianzuo     1001

 

[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"} {if($3 >= 500) printf "%-15s%s\n",$1,$3}' /etc/passwd

USERNAME       UID

nfsnobody      65534

oldboy         500

mysql          501

nginx          502

nagios         503

disdata        999

ayibang        1000

liujianzuo     1001

 

[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"}{printf "%-15s%s\n",$1,$3}' /etc/passwd 

USERNAME       UID

root           0

bin            1

daemon         2

adm            3

lp             4

sync           5

shutdown       6

halt           7

mail           8

news           9

uucp           10

operator       11

games          12

gopher         13

ftp            14

nobody         99

nscd           28

vcsa           69

pcap           77

ntp            38

dbus           81

avahi          70

rpc            32

mailnull       47

smmsp          51

oprofile       16

sshd           74

rpcuser        29

nfsnobody      65534

xfs            43

haldaemon      68

avahi-autoipd  100

oldboy         500

mysql          501

nginx          502

nagios         503

disdata        999

ayibang        1000

liujianzuo     1001

 

End应用 添加表尾

[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"} {$3>=500;printf "%-15s%s\n",$1,$3}END{printsswd "END"}' /etc/passwd          

USERNAME       UID

root           0

bin            1

daemon         2

adm            3

lp             4

sync           5

shutdown       6

halt           7

mail           8

news           9

uucp           10

operator       11

games          12

gopher         13

ftp            14

nobody         99

nscd           28

vcsa           69

pcap           77

ntp            38

dbus           81

avahi          70

rpc            32

mailnull       47

smmsp          51

oprofile       16

sshd           74

rpcuser        29

nfsnobody      65534

xfs            43

haldaemon      68

avahi-autoipd  100

oldboy         500

mysql          501

nginx          502

nagios         503

disdata        999

ayibang        1000

liujianzuo     1001

END

 

 

 

BEGIN 赋值

[root@centos5 ceshi]# awk -F : '{print $1}' /etc/passwd |head -1

root

[root@centos5 ceshi]# awk -v FS=: '{print $1}' /etc/passwd |head -1

root

[root@centos5 ceshi]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd |head -1           

root

 

控制语句

 

如果if后面是好几个条件应该用花括号扩起来

 

If案例

[root@centos5 ~]# awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd

8

[root@centos5 ~]# awk -F: '{if ($3>=500) print $NF}' /etc/passwd 

/sbin/nologin

/bin/bash

/sbin/nologin

/sbin/nologin

/sbin/nologin

/bin/bash

/bin/bash

/bin/bash

[root@centos5 ~]# awk -F: '{if ($3>=500) print $NF}' /etc/passwd|wc -l

8

 

[root@centos5 ceshi]# awk -F: '{if ($3 == 0) print $1,"Admin";else print $1,"Comman user"}' /etc/passwd

root Admin

bin Comman user

daemon Comman user

adm Comman user

lp Comman user

sync Comman user

shutdown Comman user

halt Comman user

mail Comman user

news Comman user

uucp Comman user

operator Comman user

games Comman user

gopher Comman user

ftp Comman user

nobody Comman user

nscd Comman user

vcsa Comman user

pcap Comman user

ntp Comman user

dbus Comman user

avahi Comman user

rpc Comman user

mailnull Comman user

smmsp Comman user

oprofile Comman user

sshd Comman user

rpcuser Comman user

nfsnobody Comman user

xfs Comman user

haldaemon Comman user

avahi-autoipd Comman user

oldboy Comman user

mysql Comman user

nginx Comman user

nagios Comman user

disdata Comman user

ayibang Comman user

liujianzuo Comman user

 

 

While案例

[root@centos5 ~]# awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd  

root

x

0

bin

x

1

daemon

x

2

adm

x

3

lp

x

4

sync

x

5

shutdown

x

6

halt

x

7

mail

x

8

news

x

9

uucp

x

10

operator

x

11

games

x

12

gopher

x

13

ftp

x

14

nobody

x

99

nscd

x

28

vcsa

x

69

pcap

x

77

ntp

x

38

dbus

x

81

avahi

x

70

rpc

x

32

mailnull

x

47

smmsp

x

51

oprofile

x

16

sshd

x

74

rpcuser

x

29

nfsnobody

x

65534

xfs

x

43

haldaemon

x

68

avahi-autoipd

x

100

oldboy

x

500

mysql

x

501

nginx

x

502

nagios

x

503

disdata

x

999

ayibang

x

1000

liujianzuo

x

1001

Awk可以加pattion 模式的意思,如果不匹配pattion意指其会每行都匹配。

[oldboy@centos5 ~]$ awk -F: '$1 !~ /^root/{i=1;while (i<=2) {print $i;i++}}' /etc/passwd

bin

x

daemon

x

adm

x

lp

x

sync

x

shutdown

x

halt

x

mail

x

news

x

uucp

x

operator

x

games

x

gopher

x

ftp

x

nobody

x

nscd

x

vcsa

x

pcap

x

ntp

x

dbus

x

avahi

x

rpc

x

mailnull

x

smmsp

x

oprofile

x

sshd

x

rpcuser

x

nfsnobody

x

xfs

x

haldaemon

x

avahi-autoipd

x

oldboy

x

mysql

x

nginx

x

nagios

x

disdata

x

ayibang

x

liujianzuo

X

例如我想取第第奇数个字段。我们递增i+=2即可

[oldboy@centos5 ~]$ awk -F: '$3 >= 500{i=1;while (i<=4) {print $i;i+=2}}' /etc/passwd            

Nfsnobody  #第一列

65534   #第三列

Oldboy #第一列

500  #第三列

mysql

501

nginx

502

nagios

503

disdata

999

ayibang

1000

liujianzuo

1001

 

do-while 无论条件如何,首先会循环一遍,当条件一满足就会退出

 

 

用awk的while循环计算1+。。。+100

 

[root@centos5 awk]# awk 'BEGIN{i=1;while (i<=100) {sum+=i;print sum;i++}}' |tail -1

5050

awk 'BEGIN{i=1;do {sum+=i;print sum;i++}while(i<=100)}'|tail -1

5050

awk 'BEGIN{i=1;do {sum=sum+i;print sum;i++}while(i<=100)}'|tail -1  

5050

 

 

awk 'BEGIN{i=1;do {sum+=i;i++}while(i<=100) print sum}' 

【元婴】北京-吴兆 2015/1/11 17:53:30

循环中不输出,最后输出结构就行了…… 

 

 

 

 

 

For循环案例

cat filename | nawk -F " "  '{for (i=4;i<=NF;i++)printf("%s ", $i);print ""}'  字段不换行 printf

 

[root@centos5 awk]# awk -F: '$3>=500{for (i=1;i<=NF;i+=2) print $i}' /etc/passwd 

awk -F: '$3>=500{for (i=1;i<=NF;i+=2) printf("%s ", $i);print ""}' /etc/passwd 

 

nfsnobody

65534

Anonymous NFS User

/sbin/nologin

oldboy

500

 

/bin/bash

mysql

501

 

/sbin/nologin

nginx

502

 

/sbin/nologin

nagios

503

 

/sbin/nologin

disdata

999

 

/bin/bash

ayibang

1000

 

/bin/bash

liujianzuo

1001

 

/bin/bash

for打印第奇数个字段

[root@centos5 awk]# awk -F: '$3>=500{for (i=1;i<=5;i+=2) print $i}' /etc/passwd  

nfsnobody

65534

Anonymous NFS User

oldboy

500

 

mysql

501

 

nginx

502

 

nagios

503

 

disdata

999

 

ayibang

1000

 

liujianzuo

1001

Awk 的For循环的1加到100

[root@centos5 awk]# awk 'BEGIN{for (i=i;i<=100;i++) {j=j+i;print j}}'|tail -1

5050

 

[root@ayibang-server /server/scripts]# awk 'BEGIN{j=0;for (i=1;i<=100;i++) j+=i;{print j}}'
5050

 

 

 

 

 

 

 

 

Awk的内置变量

 

内置变量

    以下为awk内置变量:

          ARGC        命令行参数个数

          FILENAME    当前输入文档的名称

          FNR        当前输入文档的当前记录编号,尤其当有多个输入文档时有用

          NR        输入流的当前记录编号

          NF        当前记录的字段个数

          FS        字段分隔符

          OFS        输出字段分隔符,默认为空格

          ORS        输出记录分隔符,默认为换行符\n

          RS        输入记录分隔符,默认为换行符\n

示例:

Awk的引用shell中的参数

[liujianzuo@w2 scripts]$  for n in {06..26};do for i in `ls -l /data1/logs/qr* |awk '{print $NF}'`;do wc -l $i|awk -F . '$NF ~ /201507'${n}'/{print $0}';done;done                                  1 /data1/logs/qrscene_51pro_gz.log.20150707

6 /data1/logs/qrscene_51pro_hz.log.20150707

2 /data1/logs/qrscene_51pro_nj.log.20150707

3 /data1/logs/qrscene_51pro_qd.log.20150707

1 /data1/logs/qrscene_51pro_sh.log.20150707

6 /data1/logs/qrscene_51pro_wh.log.20150707

1 /data1/logs/qrscene_51pro_xa.log.20150707

1 /data1/logs/qrscene_51pro_zz.log.20150707

4 /data1/logs/qrscene_cq_dm.log.20150707

5 /data1/logs/qrscene_cq_sl.log.20150707

17 /data1/logs/qrscene_cs_dm.log.20150707

1 /data1/logs/qrscene_gz_dm.log.20150707

1 /data1/logs/qrscene_gz_szi.log.20150707

6 /data1/logs/qrscene_hz_dm.log.20150707

9 /data1/logs/qrscene_mlyh.log.20150707

2 /data1/logs/qrscene_nj_dm.log.20150707

3 /data1/logs/qrscene_nj_sl.log.20150707

1 /data1/logs/qrscene_qd_szi.log.20150707

1 /data1/logs/qrscene_xa_szi.log.20150707

14 /data1/logs/qrscene_xiaomi.log.20150707

26 /data1/logs/qrscene_xz.log.20150707

4 /data1/logs/qrscene_zz_dm.log.20150707

3 /data1/logs/qrscene_15suit.log.20150708

5 /data1/logs/qrscene_51pro_bj.log.20150708

1 /data1/logs/qrscene_51pro_gz.log.20150708

5 /data1/logs/qrscene_51pro_hz.log.20150708

19 /data1/logs/qrscene_51pro_qd.log.20150708

1 /data1/logs/qrscene_51pro_wh.log.20150708

。。。。。略去n行

 

 

http://oldboy.blog.51cto.com/2561410/760192 

问题为:

4)已知:/etc/hosts的内容为

192.168.1.11  oldboy11.etiantian.org

192.168.1.21  oldboy21.etiantian.org

192.168.1.31  oldboy31.etiantian.org

#192.168.1.111  oldboy111.etiantian.org

请用shell脚本实现,怎么才能在输入IP后找到/etc/hosts里对应的唯一的hostname?

解答:

法1)脚本过滤法

[root@old_boy scripts]# cat judgehost.sh   

#!/bin/bash  

echo "please input ip address:" 

read ip  

[ -n "`grep "$ip " /etc/hosts`" ] && \  #注意前面的过滤条件结尾带有空格。  

echo "The hostname is: `grep "$ip " /etc/hosts |awk '{print $2}'`" || \  

echo "The ip is invalid" 

 提示:

1)这是一个grep过滤加条件判断的实现语法:

2)条件判断语法为[ -n "ddd" ] && echo 1 || echo 0

3)[ -n "`grep "$ip " /etc/hosts`" ] && \  #注意前面的过滤条件结尾带有空格。这里啊,是为了排除下面的重复情况

 192.168.1.11  oldboy11.etiantian.org

 192.168.1.111  oldboy111.etiantian.org

----------------我是每种方法分隔符---------------

法2)脚本精确匹配法:

#!/bin/bash  

#author oldboy  

#qq 31333741  

#judge input  

if [ $# -ne 1 ]  

  then 

    echo "input error!" 

    exit 1  

fi  

 

flag=0  

exec < /etc/hosts  

while read line  

do  

 if [ "$1" = "`echo $line|awk '{print $1}'`" ]  

   then 

       flag=1  

       echo "the $1 's hostname is `echo $line|awk '{print $2}'`"   

       break;  

 fi  

done   

[ $flag -eq 0 ] && echo " sorrry,not find $1 's hostname!" 

 

提示:此题,请大家学习while的用法及设置flag的思路。

执行结果:

[root@old_boy scripts]# sh oldboy.sh 192.168.1.11

the 192.168.1.11 's hostname is oldboy11.etiantian.org

[root@old_boy scripts]# sh oldboy.sh 192.168.1.21

the 192.168.1.21 's hostname is oldboy21.etiantian.org

[root@old_boy scripts]# sh oldboy.sh 192.168.1.311

 sorrry,not find 192.168.1.311 's hostname!

----------------我是每种方法分隔符---------------

 

特别提示:下面的方法中,老男孩老师大量的使用了awk的不同方法来实现同样的功能,来告诉大家,awk是很强大的, 希望同学们能按照老师的教学要求精通之。

法3)awk精确匹配:

准备:

[root@old_boy scripts]# tail -4 /etc/hosts

192.168.1.11  oldboy11.etiantian.org

192.168.1.111  oldboy111.etiantian.org

192.168.1.21  oldboy21.etiantian.org

192.168.1.31  oldboy31.etiantian.org

脚本:

[root@old_boy scripts]# cat awkhost1.sh   

awk 'BEGIN {a="'$1'"} {if($1==a) print $2; }' /etc/hosts  

执行结果:

[root@old_boy scripts]# sh awkhost1.sh 192.168.1.21

oldboy21.etiantian.org

[root@old_boy scripts]# sh awkhost1.sh 192.168.1.31

oldboy31.etiantian.org

[root@old_boy scripts]# sh awkhost1.sh 192.168.1.11

oldboy11.etiantian.org

提示:注意a="'$1'"的用法,$1为命令行传参。awk程序中调用系统变量的方法a="'$1'"。

----------------我是每种方法分隔符---------------

法4)awk精确匹配法

[root@old_boy scripts]# cat awkhost2.sh   

awk '{if($1=="'$1'") print $2}' /etc/hosts  

执行结果:

[root@old_boy scripts]# awkhost2.sh 192.168.1.11

oldboy11.etiantian.org

[root@old_boy scripts]# awkhost2.sh 192.168.1.21

oldboy21.etiantian.org

[root@old_boy scripts]# awkhost2.sh 192.168.1.311

----------------我是每种方法分隔符---------------

法5)awk过滤法

[root@old_boy scripts]# cat awkhost4.sh   

awk '/'"${1} "'/''{print $2}' /etc/hosts  

执行结果:  

[root@old_boy scripts]# awkhost4.sh 192.168.1.21  

oldboy21.etiantian.org  

[root@old_boy scripts]# awkhost4.sh 192.168.1.11  

oldboy11.etiantian.org  

[root@old_boy scripts]# awkhost4.sh 192.168.1.31  

oldboy31.etiantian.org  

提示:除了语法外,这道题有个学问,就是过滤时传参结尾要带个空格,这样才能过滤重复IP的情况  

如:  

 192.168.1.11  oldboy11.etiantian.org  

 192.168.1.111  oldboy111.etiantian.org 

----------------我是每种方法分隔符---------------

法6)awk过滤法

[root@old_boy scripts]# cat awkhost5.sh   

awk '{if($1~/'$1'/) print $2}'  /etc/hosts ##如果文件第一列包含命令行第一个参数字符则打印第二列  

执行结果:  

[root@old_boy scripts]# awkhost5.sh 192.168.1.31  

oldboy31.etiantian.org  

[root@old_boy scripts]# awkhost5.sh 192.168.1.11  

oldboy11.etiantian.org  

oldboy111.etiantian.org ------>这里有bug了。  

[root@old_boy scripts]# awkhost5.sh 192.168.1.21  

oldboy21.etiantian.org  

改进下来排除bug:  

[root@old_boy scripts]# cat awkhost5-1.sh   

awk '{if($1~/'$1' /) print $2}'  /etc/hosts ==>用上面加空格的思路不对。  

[root@old_boy scripts]# cat awkhost5-1.sh   

awk '{if($1~/'$1'$/) print $2}'  /etc/hosts #增加一个正则表达式$  

执行结果:  

[root@old_boy scripts]# awkhost5-1.sh 192.168.1.21  

oldboy21.etiantian.org  

[root@old_boy scripts]# awkhost5-1.sh 192.168.1.11  

oldboy11.etiantian.org  

[root@old_boy scripts]# awkhost5-1.sh 192.168.1.31  

oldboy31.etiantian.org 

----------------我是每种方法分隔符---------------

法7)awk -v精确匹配法

 

命令行测试:  

[root@old_boy scripts]# awk -v p=192.168.1.21 '$1 == p{print $2}' /etc/hosts  

oldboy21.etiantian.org  

[root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p{print $2}' /etc/hosts  

oldboy11.etiantian.org  

[root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p {print $2}' /etc/hosts  

oldboy11.etiantian.org  

实际脚本: 

[root@old_boy scripts]# cat awkhost6.sh   

#!/bin/bash  

#p=$1  

#awk -v p="$p" '$1 == p{print $2}' /etc/hosts  

awk -v p="$1" '$1 == p{print $2}' /etc/hosts 

执行结果:

[root@old_boy scripts]# sh  awkhost6.sh  192.168.1.11

oldboy11.etiantian.org

[root@old_boy scripts]# sh  awkhost6.sh  192.168.1.21

oldboy21.etiantian.org

提示:

1)传参非awk程序,因此写法p="$1"

2)man awk

       -v var=val

       --assign var=val

              Assign the value val to the variable var, before execution of the program begins.   Such  vari-

              able values are available to the BEGIN block of an AWK program.

----------------我是每种方法分隔符---------------

法8:精确匹配简单的写法

[root@old_boy scripts]# cat awkhost9.sh   

awk  '$1 == "'$1'" {print $2}' /etc/hosts  

执行结果:  

[root@old_boy scripts]# sh awkhost9.sh  192.168.1.11  

oldboy11.etiantian.org  

[root@old_boy scripts]# sh awkhost9.sh  192.168.1.21  

oldboy21.etiantian.org  

[root@old_boy scripts]# sh awkhost9.sh  192.168.1.31  

oldboy31.etiantian.org  

特别提示:这里老男孩老师大量的使用了awk的不同方法来实现同样的功能,很强大吧,  

希望同学们能按照老师的教学要求精通之。 

 

 

Awk的 数组

 

 

 

数组就是变量的即集合体

 

Shell中的打印 echo ${A["x"]} 需要${}才能输出变量,而awk则不用

下标可以是任意字符,但是我们要将字符用引号引起来,以免被误认为变量

如下

[root@centos5 ~]# awk 'BEGIN{A[x]='hello';A[y]='world';print A[x]}'

 

[root@centos5 ~]# awk 'BEGIN{A["x"]='hello';A["y"]='world';print A[x],A["y"]}'   

 

[root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";print A[x],A["y"]}'    

 world

[root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";print A["x"],A["y"]}'

hello world

 

 

 

 

 

Awk的数组不能跟shell的数组一样,不能一一遍历,它的元素不都是数字,有可能是字符串或者字段

 

第二个是for循环是awk的遍历,这里面的ARRAY是数组,A是我们定义的变量是数组的下标数字0 1 2 3 。。。  A保存的是我们数组ARRAY的下标名字

 

例如

[root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";for (B in A) print A[B]}'   #这里的B是定义的变量就是A数组的下标号,我们遍历A数组,打印所有的元素。B保存的是A数组的下标名字                           

hello

world

 

 

 

例一:awk过滤统计tcp连接状态的个数

Tcp状态有好多种,最后一列,我们用awk实现统计每种状态的连接数 后面有解释

[root@centos5 ~]# netstat -ant

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address               Foreign Address             State      

tcp        0      0 0.0.0.0:2049                0.0.0.0:*                   LISTEN      

tcp        0      0 0.0.0.0:5666                0.0.0.0:*                   LISTEN      

tcp        0      0 127.0.0.1:199               0.0.0.0:*                   LISTEN      

tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      

tcp        0      0 0.0.0.0:624                 0.0.0.0:*                   LISTEN      

tcp        0      0 0.0.0.0:22929               0.0.0.0:*                   LISTEN      

tcp        0      0 0.0.0.0:52113               0.0.0.0:*                   LISTEN      

tcp        0      0 0.0.0.0:1012                0.0.0.0:*                   LISTEN      

tcp        0      0 192.168.92.132:52113        192.168.92.1:49262          ESTABLISHED 

tcp        0      0 :::52113                    :::*                        LISTEN

 

解释例子

Awk的数组组成:数组名字,数组下标,数组元素,数组元素的值。

S[$NF]++ 意思是我们这个数组S,我们取最后一列作为这个数组的下标,因此这个数组就是S[LISTEN] S[ESTABLISHED],每读取一行,相同元素会叠加

 

这里A是数组S的下标名称,而数组S的下标名称是TIME_WAIT  CLOSE_WAIT   FIN_WAIT1  ESTABLISHED  等等。For循环是遍历的这几种,所以A就代表这几个名称,而S[A]则代表数组元素的值

 

[ayibang@db2 ~]$ netstat -ant|awk '$1~/tcp/{S[$NF]++}END{for (A in S) print A,S[A]}' 

TIME_WAIT 1789

CLOSE_WAIT 38

FIN_WAIT1 6

ESTABLISHED 94

SYN_RECV 3

LAST_ACK 3

LISTEN 23

 

或者用ss命令取值

[ayibang@db2 ~]$ ss -ant |awk '{S[$1]++}END{for (A in S) printf "%4s,%4s\n",S[A],A}'

   8,LAST-ACK

   3,SYN-RECV

 292,ESTAB

   1,State

   4,FIN-WAIT-1

   3,CLOSING

   8,FIN-WAIT-2

6469,TIME-WAIT

  41,CLOSE-WAIT

  23,LISTEN

例二:awk 完成/etc/passwd 取最后一个字段同种shell解释类型的个数,排除空行

[root@centos5 ~]# awk -F: '$NF!~/^$/{SHELL[$NF]++}END{for(A in SHELL) printf "%16s:%s\n",A,SHELL[A]}' /etc/passwd 

  /sbin/shutdown:1

       /bin/bash:5

   /sbin/nologin:30

      /sbin/halt:1

       /bin/sync:1

 

 

 

例三:查看访问日志ip;

[root@db2 logs]# awk '{IP[$1]++}END{for (A in IP) printf "%20s:%5s\n",A,IP[A]}' access_www.log |sort -rn|head

          223.9.2.89:   37

      223.68.131.168:   31

       223.243.41.89:    1

      223.240.233.91:   34

      223.223.194.23:   50

     223.223.194.215:   16

      223.167.19.183:   65

     223.166.112.132:    1

        223.104.5.30:   69

         223.104.5.2:    2

Awik的内置函数

 

例一 :统计客户端连接80端口的ip个数,netstat 的第五列 (判断黑客攻击的统计)

split($5,client,":")含义如下

ه内置函数split 先把第五个字段,以:为分隔符,切割新的字段,保存成client数组,

IP[client[1]]++}END{for (i in IP){print IP[i],i}}'

以新的IP数组,client数组第一列为新数组IP下标,最后做做求和,统计个数 

split是函数  用小括号…………

 

[root@db2 ~]# netstat -ant|awk '/:80/{split($5,client,":");IP[client[1]]++}END{for (i in IP){print IP[i],i}}'|sort -rn |head

10 116.247.112.153

6 210.22.62.180

6 123.125.65.237

5 123.138.215.24

3 221.237.44.110

3 111.202.0.53

3 106.2.195.214

2 117.79.81.51

2 101.80.175.17

2 0.0.0.0

 

 

 

 

 

 

 

 

 

 

Awk练习 

需求:awk实现每一行对应字段的数字相加

a文件
11 23
13 23
43 56
b文件
11 43
45 455
32 23


输出结果如下
22 66
58 478
75 79

 

 

解答:

awk '{a[FNR]+=$1;b[FNR]+=$2} END{for(i in a){print a[i],b[i]}}' cc1.log cc2.log 

 

awk '{n=FNR;a[n]+=$1;b[n]+=$2} END{for(i=1;i<=n;i++){print a[i],b[i]}}' cc1.log cc2.log

 

awk '{n=FNR;a[n]+=$1;b[n]+=$2; if(NR > n) print a[n],b[n]}' cc1.log cc2.log   

 

awk '{n=FNR;a[n]+=$1;b[n]+=$2} NR > n {print a[n],b[n]}' cc1.log cc2.log

 

awk '{if(NR == FNR){a[NR]=$1;b[NR]=$2}else{print $1+a[FNR],$2+b[FNR]}}' cc1.log cc2.log 

 

 

awk 'NR==FNR {a[NR]=$1;b[NR]=$2;next} {print $1+a[FNR],$2+b[FNR]}' cc1.log cc2.log 

 

paste cc1.log cc2.log |awk '{print $1+$3,$2+$4}'

 

awk 'NR == FNR{a[i]=$1;b[i]=$2;i++} NR>FNR{print $1+a[j],$2+b[j];j++}' cc1.log cc2.log 

 

 

 

 

 

Awk sed 练习

20150418周末小题

原始数据:

17/Apr/2015:09:29:24 +0800

17/Apr/2015:09:30:26 +0800

17/Apr/2015:09:31:56 +0800

18/Apr/2015:09:34:12 +0800

18/Apr/2015:09:35:23 +0800

19/Apr/2015:09:23:34 +0800

19/Apr/2015:09:22:21 +0800

20/Apr/2015:09:45:22 +0800

期望结果:

2015-04-17 09:29:24+0800

2015-04-17 09:30:26+0800

2015-04-17 09:31:56+0800

2015-04-18 09:34:12+0800

2015-04-18 09:35:23+0800

2015-04-19 09:23:34+0800

2015-04-19 09:22:21+0800

2015-04-20 09:45:22+0800

 

解决实践:来自运维21期悠久之翼 群内分享

[root@web01 ~]# cat oldboy.txt 

17/Apr/2015:09:29:24 +0800

17/Apr/2015:09:30:26 +0800

17/Apr/2015:09:31:56 +0800

18/Apr/2015:09:34:12 +0800

18/Apr/2015:09:35:23 +0800

19/Apr/2015:09:23:34 +0800

19/Apr/2015:09:22:21 +0800

20/Apr/2015:09:45:22 +0800

 

 

[root@web01 ~]# awk '{sub(/Apr/,"04");split($0,array,"[/: ]") ;printf("%s-%s-%s %s:%s:%s%s\n",array[3],array[2],array[1],array[4],array[5],array[6],array[7])}' oldboy.txt 

2015-04-17 09:29:24+0800

2015-04-17 09:30:26+0800

2015-04-17 09:31:56+0800

2015-04-18 09:34:12+0800

2015-04-18 09:35:23+0800

2015-04-19 09:23:34+0800

2015-04-19 09:22:21+0800

2015-04-20 09:45:22+0800

 

1. sub函数

 

[root@nhserver1 10]# echo "a b c 2011-11-22 a:d" | awk 'sub(/-/,"",$4)'

a b c 201111-22 a:d

 

 

2. gsub函数

 

[root@nhserver1 10]# echo "a b c 2011-11-22 a:d" | awk 'gsub(/-/,"",$4)'

a b c 20111122 a:d

 

 

sub函数只实现第一个位置的替换,gsub函数实现全局的替换。

Split切割是第一列下表是1

 

 

[root@web01 ~]# sed -nr 's#(..)/(...)/(....):(..):(..):(..) (.*)#\3-\2-\1 \4:\5:\6\7#;s#Apr#04#p' oldboy.txt 

2015-04-17 09:29:24+0800

2015-04-17 09:30:26+0800

2015-04-17 09:31:56+0800

2015-04-18 09:34:12+0800

2015-04-18 09:35:23+0800

2015-04-19 09:23:34+0800

2015-04-19 09:22:21+0800

2015-04-20 09:45:22+0800

 

. 是一个字符, s是替换  p打印

 

Sed 扩展

在编写shell脚本的过程中,我们经常需要使用sed流编辑器和awk对文本文件进行处理。

一、什么是sed

    sed 是一种在线编辑器,它一次处理一行内容。sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。

 

二、sed的处理过程

    sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程如下:首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed便结束运行。

   前面说到sed不会修改文件,那么现在我们可以知道是为什么了?是因为sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。

补充知识:

    在使用sed的过程中,我们经常会听到“定址”,那么什么是“定址”呢?

    定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。

1、地址是一个数字,则表示行号;是“$"符号,则表示最后一行。

例如:

[plain] view plaincopy

  1. sed -n '3p' datafile   #只打印第三行  

 

2、只显示指定行范围的文件内容

例如:

[plain] view plaincopy

  1. sed -n '100,200p' mysql_slow_query.log  # 只查看文件的第100行到第200行  

 

3、地址是逗号分隔的,那么需要处理的地址是这两行之间的范围(包括这两行在内)。范围可以用数字、正则表达式、或二者的组合表示。

例如:

[plain] view plaincopy

  1. sed '2,5d' datafile  
  2. #删除第二到第五行  
  3. sed '/My/,/You/d' datafile  
  4. #删除包含"My"的行到包含"You"的行之间的行  
  5. sed '/My/,10d' datafile  
  6. #删除包含"My"的行到第十行的内容  

 

三、sed命令和选项

sed命令告诉sed如何处理由地址指定的各输入行,如果没有指定地址则处理所有的输入行。

1、sed命令

 

 命令

 功能

 a\

 在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行

 c\

 用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用"\"续行

 i\

 在当前行之前插入文本。多行时除最后一行外,每行末尾需用"\"续行

 d

 删除行

 h

 把模式空间里的内容复制到暂存缓冲区

 H

 把模式空间里的内容追加到暂存缓冲区

 g

 把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容

 G

 把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面

 l

 列出非打印字符

 p

 打印行

 n

 读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理

 q

 结束或退出sed

 r

 从文件中读取输入行

 !

 对所选行以外的所有行应用命令

 s

 用一个字符串替换另一个

 g

 在行内进行全局替换

 w

 将所选的行写入文件

 x

 交换暂存缓冲区与模式空间的内容

 y

 将字符替换为另一字符(不能对正则表达式使用y命令)

 

2、sed选项

 

 选项

 功能

 -e

 进行多项编辑,即对输入行应用多条sed命令时使用

 -n

 取消默认的输出

 -f

 指定sed脚本的文件名

 

四、正则表达式元字符

    与grep一样,sed也支持特殊元字符,来进行模式查找、替换。不同的是,sed使用的正则表达式是括在斜杠线"/"之间的模式。

    如果要把正则表达式分隔符"/"改为另一个字符,比如o,只要在这个字符前加一个反斜线,在字符后跟上正则表达式,再跟上这个字符即可。

例如:

[plain] view plaincopy

  1. sed -n '\o^Myop' datafile  


常用的正则表达式如下:

 元字符

 功能

 示例

 ^

 行首定位符

 /^my/ 匹配所有以my开头的行

 $

 行尾定位符

 /my$/ 匹配所有以my结尾的行

 .

 匹配除换行符以外的单个字符

 /m..y/ 匹配包含字母m,后跟两个任意字符,再跟字母y的行

 *

 匹配零个或多个前导字符

 /my*/ 匹配包含字母m,后跟零个或多个y字母的行

 []

 匹配指定字符组内的任一字符

 /[Mm]y/ 匹配包含My或my的行

 [^]

 匹配不在指定字符组内的任一字符

 /[^Mm]y/ 匹配包含y,但y之前的那个字符不是M或m的行

 ..

 保存已匹配的字符

 1,20s/youself/\1r/ 标记元字符之间的模式,并将其保存为标签1,之后可以使用\1来引用它。最多可以定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,如果发现youself,则替换为your。

 &

 保存查找串以便在替换串中引用

 s/my/**&**/  符号&代表查找串。my将被替换为**my**

 \<

 词首定位符

 /\<my/ 匹配包含以my开头的单词的行

 \>

 词尾定位符

 /my\>/ 匹配包含以my结尾的单词的行

 x\{m\}

 连续m个x

 /9\{5\}/匹配包含连续5个9的行

 x\{m,\}

 至少m个x

 /9\{5,\}/ 匹配包含至少连续5个9的行

 x\{m,n\}

 至少m个,但不超过n个x

 /9\{5,7\}/ 匹配包含连续5到7个9的行

 

五、sed的退出状态

    sed不向grep一样,不管是否找到指定的模式,它的退出状态都是0。只有当命令存在语法错误时,sed的退出状态才不是0。

六、常用范例

1、p命令

    命令p用于显示模式空间的内容。默认情况下,sed把输入行打印在屏幕上,选项-n用于取消默认的打印操作。当选项-n和命令p同时出现时,sed可打印选定的内容。

例子:

[plain] view plaincopy

  1. (1)sed '/my/p' datafile  
  2. #默认情况下,sed把所有输入行都打印在标准输出上。如果某行匹配模式my,p命令将把该行另外打印一遍。  
  3. (2)sed -n '/my/p' datafile  
  4. #选项-n取消sed默认的打印,p命令把匹配模式my的行打印一遍。  

 

2、d命令

    命令d用于删除输入行。sed先将输入行从文件复制到模式空间里,然后对该行执行sed命令,最后将模式空间里的内容显示在屏幕上。如果发出的是命令d,当前模式空间里的输入行会被删除,不被显示。

例子:

[plain] view plaincopy

  1. (1)sed '$d' datafile  
  2. #删除最后一行,其余的都被显示  
  3. (2)sed '/my/d' datafile  
  4. #删除包含my的行,其余的都被显示  

 

3、s命令

例子:

[plain] view plaincopy

  1. (1)sed 's/^My/You/g' datafile  
  2. #命令末端的g表示在行内进行全局替换,也就是说如果某行出现多个My,所有的My都被替换为You。  
  3. (2)sed -n '1,20s/My$/You/gp' datafile  
  4. #取消默认输出,处理1到20行里匹配以My结尾的行,把行内所有的My替换为You,并打印到屏幕上。  
  5. (3)sed 's#My#Your#g' datafile  
  6. #紧跟在s命令后的字符就是查找串和替换串之间的分隔符。分隔符默认为正斜杠,但可以改变。无论什么字符(换行符、反斜线除外),只要紧跟s命令,就成了新的串分隔符。  


 

4、e选项

   -e是编辑命令,用于sed执行多个编辑任务的情况下。在下一行开始编辑前,所有的编辑动作将应用到模式缓冲区中的行上。

例子:

[plain] view plaincopy

  1. sed -e '1,10d' -e 's/My/Your/g' datafile  
  2. #选项-e用于进行多重编辑。第一重编辑删除第1-3行。第二重编辑将出现的所有My替换为Your。因为是逐行进行这两项编辑(即这两个命令都在模式空间的当前行上执行),所以编辑命令的顺序会影响结果。  

 

5、r命令

r命令是读命令。sed使用该命令将一个文本文件中的内容加到当前文件的特定位置上。

例如:

[plain] view plaincopy

  1. sed '/My/r introduce.txt' datafile  
  2. #如果在文件datafile的某一行匹配到模式My,就在该行后读入文件introduce.txt的内容。如果出现My的行不止一行,则在出现My的各行后都读入introduce.txt文件的内容。  

 

6、w命令

例子:

[plain] view plaincopy

  1. sed -n '/hrwang/w me.txt' datafile  

 

7、a\ 命令

    a\ 命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面。所追加的文本行位于sed命令的下方另起一行。如果要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外。最后一行将以引号和文件名结束。

例子:

[plain] view plaincopy

  1. sed '/^hrwang/a\  
  2. >hrwang and mjfan are husband\  
  3. >and wife' datafile  
  4. #如果在datafile文件中发现匹配以hrwang开头的行,则在该行下面追加hrwang and mjfan are husband and wife  

 

8、i\ 命令

i\ 命令是在当前行的前面插入新的文本。

 

9、c\ 命令

sed使用该命令将已有文本修改成新的文本。

 

10、n命令

sed使用该命令获取输入文件的下一行,并将其读入到模式缓冲区中,任何sed命令都将应用到匹配行紧接着的下一行上。

例如:

[plain] view plaincopy

  1. sed '/hrwang/{n;s/My/Your/;}' datafile  

注:如果需要使用多条命令,或者需要在某个地址范围内嵌套地址,就必须用花括号将命令括起来,每行只写一条命令,或这用分号分割同一行中的多条命令。

 

11、y命令

    该命令与UNIX/Linux中的tr命令类似,字符按照一对一的方式从左到右进行转换。例如,y/abc/ABC/将把所有小写的a转换成A,小写的b转换成B,小写的c转换成C。

例如:

[plain] view plaincopy

  1. sed '1,20y/hrwang12/HRWANG^$/' datafile  
  2. #将1到20行内,所有的小写hrwang转换成大写,将1转换成^,将2转换成$。  
  3. #正则表达式元字符对y命令不起作用。与s命令的分隔符一样,斜线可以被替换成其它的字符。  

 

12、q命令

    q命令将导致sed程序退出,不再进行其它的处理。

[plain] view plaincopy

  1. sed '/hrwang/{s/hrwang/HRWANG/;q;}' datafile  

 

13、h命令和g命令

为了更好说明这两个命令,我们先创建如下的文本文件:

[plain] view plaincopy

  1. #cat datafile  
  2. My name is hrwang.  
  3. Your name is mjfan.  
  4. hrwang is mjfan's husband.  
  5. mjfan is hrwang's wife.  

 

[plain] view plaincopy

  1. sed -e '/hrwang/h' -e '$G' datafile  
  2. sed -e '/hrwang/H' -e '$G' datafile  
  3. #通过上面两条命令,你会发现h会把原来暂存缓冲区的内容清除,只保存最近一次执行h时保存进去的模式空间的内容。而H命令则把每次匹配hrwnag的行都追加保存在暂存缓冲区。  
  4. sed -e '/hrwang/H' -e '$g' datafile  
  5. sed -e '/hrwang/H' -e '$G' datafile  
  6. #通过上面两条命令,你会发现g把暂存缓冲区中的内容替换掉了模式空间中当前行的内容,此处即替换了最后一行。而G命令则把暂存缓冲区的内容追加到了模式空间的当前行后。此处即追加到了末尾。  

 

补充知识点:sed特殊用法

[plain] view plaincopy

  1. sed -n '/root/w a.txt'    #将匹配行输出到文件  
  2. sed '/root/r abc.txt' /etc/passwd #把abc.txt的文件内容读入到root匹配行后  
  3. sed -n '/root/w a.txt'  
  4. sed -n '/root/{=;p}' /etc/passwd #打印行号和匹配root的行  
  5. sed -n '/root/{n;d}' /etc/passwd #将匹配root行的下一行删除  
  6. sed -n '/root/{N;d}' /etc/passwd #将匹配root行和下一行都删除  
  7. sed '22{h;d};23,33{H;d};44G' pass  

七、sed脚本编写方法

1、从文件读入命令

[plain] view plaincopy

  1. sed -f sed.sh  

sed.sh文件内容:

[plain] view plaincopy

  1. s/root/yerik/p  
  2. s/bash/csh/p  

 

2、直接运行脚本 ./sed.sh /etc/passwd

[plain] view plaincopy

  1. #!/bib/sed -f  
  2. s/root/yerik/p  
  3. s/bash/csh/p  

八、小技巧

1、用sed 输出自己的IP 地址

[plain] view plaincopy

  1. ifconfig eth0 |sed '2p' |sed 's/^.*addr:/ /g' |sed 's/B.*$ / /g'  

 

2、在sed的命令行中引用shell变量时要使用双引号,而不是通常所用的单引号。下面是一个根据name变量的内容来删除named.conf文件中zone段的脚本:

name='zone\ "localhost"'

[plain] view plaincopy

  1. sed "/$name/,/};/d" named.conf   

 

3、保持和获取:h命令和G命令

[plain] view plaincopy

  1. $ sed -e '/test/h' -e '$G example  

    在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。

 

4、保持和互换:h命令和x命令

[plain] view plaincopy

  1. $ sed -e '/test/h' -e '/check/x' example   

   互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换。

 

 

九、练习

1,删除文件每行的第一个字符。

[plain] view plaincopy

  1. sed -n 's/^.//gp' /etc/passwd  
  2. sed -nr 's/(.)(.*)/\2/p' /etc/passwd  

 

2,删除文件每行的第二个字符。

[plain] view plaincopy

  1. sed -nr 's/(.)(.)(.*)/\1\3/p' /etc/passwd  

 

3,删除文件每行的最后一个字符。

[plain] view plaincopy

  1. sed -nr 's/.$//p' /etc/passwd  
  2. sed -nr 's/(.*)(.)/\1/p' /etc/passwd  

 

4,删除文件每行的倒数第二个字符。

[plain] view plaincopy

  1. sed -nr 's/(.*)(.)(.)/\1\3/p' /etc/passwd  

 

5,删除文件每行的第二个单词。

[plain] view plaincopy

  1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1\2\3\5/p' /etc/passwd  

 

6,删除文件每行的倒数第二个单词。

[plain] view plaincopy

  1. sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]*)/\1\2\4\5\6/p' /etc/samba/smb.conf  

 

7,删除文件每行的最后一个单词。

[plain] view plaincopy

  1. sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]*)/\1\2\4/p' /etc/samba/smb.conf  

 

8,交换每行的第一个字符和第二个字符。

[plain] view plaincopy

  1. sed -nr 's/(.)(.)(.*)/\2\1\3/p' /etc/passwd  

 

9,交换每行的第一个单词和第二个单词。

[plain] view plaincopy

  1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1\4\3\2\5/p' /etc/samba/smb.conf  

 

10,交换每行的第一个单词和最后一个单词。

[plain] view plaincopy

  1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1\4\3\2\5/p' /etc/passwd  

 

11,删除一个文件中所有的数字。

[plain] view plaincopy

  1. sed 's/[0-9]*//g' /etc/passwd  

 

12,删除每行开头的所有空格。

[plain] view plaincopy

  1. sed -n 's/^\ *//p' /etc/samba/smb.conf   
  2. sed -nr 's/( *)(.*)/\2/p' testp  

 

13,用制表符替换文件中出现的所有空格。

[plain] view plaincopy

  1. sed -n 's/\ /\t/gp' pass  

 

14,把所有大写字母用括号()括起来。

[plain] view plaincopy

  1. sed -nr 's/([A-Z])/(&)/gp' testp   
  2. sed -n 's/[A-Z]/(&)/gp' testp  

15,打印每行3次。

[plain] view plaincopy

  1. sed 'p;p' pass  

 

16,隔行删除。

[plain] view plaincopy

  1. sed -n '1~2p' pass  

 

17,把文件从第22行到第33行复制到第44行后面。

[plain] view plaincopy

  1. sed '1,21h;22h;23,33H;44G' pass  

 

18,把文件从第22行到第33行移动到第44行后面。

[plain] view plaincopy

  1. sed '22{h;d};23,33{H;d};44G' pass  

 

19,只显示每行的第一个单词。

[plain] view plaincopy

  1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)(.*)/\2/p' /etc/passwd  

 

20,打印每行的第一个单词和第三个单词。

[plain] view plaincopy

  1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\2--\4/p' /etc/passwd  

 

21,将格式为    mm/yy/dd    的日期格式换成   mm;yy;dd

[plain] view plaincopy

  1. date +%m/%Y/%d |sed -n 's#/#;#gp'  

 

22, 逆向输出

[plain] view plaincopy

  1. cat a.txt  
  2. ABC  
  3. DEF  
  4. XYZ  
  5. 输出样式变成  
  6. XYZ  
  7. DEF  
  8. ABC  

 

posted @ 2015-11-18 17:36  众里寻,阑珊处  阅读(485)  评论(0编辑  收藏  举报
返回顶部