第十二课预习

前言:awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在linux系统中已把awk链接到gawk。

1.打印某行到某行之间的内容

1.1 先看一下要求:

例如:有个文件test的内容如下:
ert
fff
**
[abcfd]
123
324
444
[rty]
**
fgfgf
怎么能截取
[abcfd]
123
324
444
[rty]
这一部分出来呢?

1.2 我们看一下这个需求好像没有什么规律其实set nu一下其实不就是打印其中几行(4-8)的内容吗

1.3 sed -n '4,8'p 1.txt //这里直接打印4-8行就可以了。

[root@localhost ~]# sed -n '4,8'p 1.txt
[abcfd]
123
324
444
[rty]

2.sed转换大小写

2.1看一下题目要求:

sed中,使用\u表示大写,\l表示小写

1. 把每个单词的第一个小写字母变大写:
sed 's/\b[a-z]/\u&/g' filename

2. 把所有小写变大写:
sed 's/[a-z]/\u&/g' filename

3. 大写变小写:
sed 's/[A-Z]/\l&/g' filename

2.2 我们还是以/etc/passwd实验一下:

1.[root@localhost ~]# sed 's/\b[a-z]/\u&/g' test.txt //第一个字母全部变成大写了
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
Operator:X:11:0:Operator:/Root:/Sbin/Nologin

2.[root@localhost ~]# sed 's/[a-z]/\u&/g' test.txt //所有的小写字母变成大写字母
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


3.[root@localhost ~]# sed 's/[A-Z]/\l&/g' test.txt //这里我们加了一行全是大写的转换以后变成
                                                     小写了
root:x:0:0:root:/root:/bin/bash
user1:x:1001:1001::/home/user1:/bin/bash
#%^^&$$$$$$$
klsjljlxcnv,mxnv


[root@localhost ~]# cat  test.txt //这是原文档
root:x:0:0:root:/root:/bin/bash
#%^^&$$$$$$$
KLSJLJLXCNV,MXNV

3. sed在某一行最后添加一个数字

3.1 在下面指定的行后面增加数字

askdj
aslkd aslkdjf3e
skdjfsdfj
sdkfjk
fsdkfjksdjfkjsdf
12sdfesdf
aslkdjfkasdjf asdlfkjaskdfj

3.2 sed 's/$/123' test.txt // "$"表示行结尾符

[root@localhost ~]# sed 's/$/123/' test.txt
root:x:0:0:root:/root:/bin/bash123
bin:x:1:1:bin:/bin:/sbin/nologin123
daemon:x:2:2:daemon:/sbin:/sbin/nologin123
adm:x:3:4:adm:/var/adm:/sbin/nologin123
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin123

4. sed删除某关键字的下一行到最后一行

4.1 看一下题目

[root@test200 ~]# cat test
a
b
c
d
e
f

4.2  sed '/c/{p;:a;N;$!ba;d}' 2.txt

[root@localhost ~]# sed '/c/{p;:a;N;$!ba;d}' 2.txt
a
b
c
定义一个标签a,匹配c,然后N把下一行加到模式空间里,匹配最后一行时,才退出标签循环,然后命令d,把这个模式空间里的内容全部清除。

if 匹配"c"
:a
追加下一行
if 不匹配"$"
goto a
最后退出循环,d命令删除。

5.打印1到100行含某个字符串的行

5.1 其实就是sed指定行范围匹配

5.2  sed -n '1,100p' test.txt|sed -n '/root/'p //这个我觉得更好理解一些

[root@localhost ~]# sed -n '1,100p' test.txt|sed -n '/root/'p
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

6.awk 中使用外部shell变量

6.1 看一下需求

如:
A=44echo "ABCD" | awk -v GET_A=$A ’{print GET_A}’
说明:-v选项用于定义参数,这里表示将变量A的值赋予GET_A。
有多少个变量需要赋值,就需要多少个-v选项。与之等价的:应用于脚本中:

附件:
cat filename
1111111:13443253456
2222222:13211222122
1111111:13643543544
3333333:12341243123
2222222:12123123123

6.2 这里其实是一个脚本

[root@localhost ~]#! /bin/bash
sort -n filename |awk -F ':' '{print $1}'|uniq >id.txt
for id in `cat id.txt`; do
        echo "[$id]"
        awk -v id2=$id -F ':' '$1==id2 {print $2}' filename  // 另外的方式为: awk -F ':' '$1=="'id'" {print $2}' filename  
done

7.awk 合并一个文件

7.1 看一下题目 将里面两个文件合并

cat 1.txt

1 aa
2 bb
3 ee
4 ss
cat 2.txt

1 ab
2 cd
3 ad
4 bd
5 de

7.2  awk 'NR==FNR{a[$1]=$2}NR>FNR{print $0,a[$1]}'  1.txt  2.txt
解释:NR表示读取的行数, FNR表示读取的当前行数,大家可以运行这个命令 awk '{print NR,FNR}' 1.txt  2.txt,比较NR和FNR
所以其实NR==FNR 就表示读取1.txt的时候。 同理NR>FNR表示读取2.txt的时候,数组a其实就相当于一个map

[root@localhost ~]# awk 'NR==FNR{a[$1]=$2}NR>FNR{print $0,a[$1]}'  1.txt  2.txt
1 ab aa
2 cd bb
3 ad ee
4 bd ss
5 de

8.把一个文件多行连接成一行 

8.1看一下这个题目 

a=`cat file`;echo $a 
应用举例:一个文件每行都有一个数字,现在需要把每行的数字用“+”连接起来。
cat a
96
1093
1855
1253
1364
1332
2308
2589
2531
1239
2164
2826
2787
2145
2617
4311
1810
2115
1235

8.2  awk '{printf("%s ",$0)}' file   // %s 后记得要有一空格,否则出来就是完全连在一起的,中间连空格都没有

[root@localhost ~]# awk '{printf ("%s+",$0)}'  a; echo ""
96+1093+1855+1253+1364+1332+2308+2589+2531+1239+2164+2826+2787+2145+2617+4311+1810+2115+1235+
这里注意,最后一个是带“+”的。echo ""  的作用是换行。

9. awk中gsub函数的使用 

9.1 把/etc/passwd中的www替换成abc

9.2 awk 'sub(/www/,"abc")' /etc/passwd  // passwd文件中把第一次出现的www替换为abc

awk 'sub(/www/,"abc")' /etc/passwd  // passwd文件中把第一次出现的www替换为abc


[root@localhost ~]# awk 'sub(/www/,"abc")' test.txt
abct

10.awk 截取指定多个域为一行

10.1 用awk指定分隔符把文本分为若干段。如何把相同段的内容弄到一行?

10.2 这个可能还需要再进一步消化一下

for i in `seq 1 7`

do

    awk -F ':' -v a=$i '{printf $a " "}' /etc/passwd

    echo 

done

11.过滤两个或多个关键词

11.1 grep 或 egrep 或awk 过滤两个或多个关键词

11.2  grep -E '123|abc' filename  // 找出文件(filename)中包含123或者包含abc的行
        egrep '123|abc' filename    //跟上面一样
        awk '/123|abc/'  filename // 同样的方法用awk实现

[root@localhost ~]# grep -E 'root|sbin' test.txt
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
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin



[root@localhost ~]# egrep 'root|sbin' test.txt
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
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin



[root@localhost ~]# awk '/root|sbin/' test.txt
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
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin

12.用awk生成以下结构文件

12.1 用awk编写生成以下结构文件的程序。( 最后列使用现在的时间,时间格式为YYYYMMDDHHMISS)  各列的值应如下所示,每增加一行便加1,共500万行。
1,1,0000000001,0000000001,0000000001,0000000001,0000000001,0000000001,2005100110101
2,2,0000000002,0000000002,0000000002,0000000002,0000000002,0000000002,2005100110101

12.2

#! /bin/bash

for i in `seq 1 5000000`; do
    n=`echo "$i"|awk '{print length($0)}'`
    export m=$[10-$n]
    export o=`perl -e '$a='0'; $b=$a x $ENV{"m"}; print $b;'`
    export j=$i
    p=`perl -e '$c=$ENV{"o"}.$ENV{"j"}; print $c;'`
    echo "$i,$i,$p,$p,$p,$p,$p,$p,`date +%Y%m%d%H%M%S`"
done
其中用到了perl,所以脚本整体看起来比较啰嗦,希望能找到更好的解决办法。
PS: shell 执行效率很低,so 该脚本运行时间会很漫长!

13.awk用print打印单引号

13.1 awk 'BEGIN{print "a'"'"'s"}'  //不用脱义,就多写几个单引号、双引号

awk 'BEGIN{print "a'\''s"}'  //用脱义,脱义的是单引号

awk 'BEGIN{print "a\"s"}'  //用脱义,脱义的是双引号

13.2

[root@localhost ~]# awk 'BEGIN{print "a'"'"'s"}'
a's
[root@localhost ~]# awk 'BEGIN{print "a'\''s"}'
a's
[root@localhost ~]# awk 'BEGIN{print "a\"s"}'
a"s

14.合并两个文件

14.1 将a.txt和b.txt里面的内容合并

举个例子。
cat  a.txt
1 2 3 
4 5 6 
a b c

cat b.txt
3 2 1 
6 5 4 
c b a 

14.2  paste  filename1  filename2 

[root@localhost ~]# paste 1.txt 2.txt
ert	a
fff	b
**	c
[abcfd]	d
123	e
324	f
444	
[rty]	
**	
fgfgf	

15.awk的BEGIN和END

15.1 BEGIN模块后紧跟着动作块,这个动作块在awk处理任何输入文件之前执行。所以它可以在没有任何输入的情况下进行测试。它通常用来改变内建变量的值,如OFS,RS和FS等,以及打印标题。如:$ awk‘BEGIN{FS=”:”; OFS=”\t”; ORS=”\n\n”}{print $1,$2,$3} test。上式表示,在处理输入文件以前,域分隔符(FS)被设为冒号,输出文件分隔符(OFS)被设置为制表符,输出记录分隔符(ORS)被设置为两个换行符。$ awk ‘BEGIN{print “TITLE TEST”}只打印标题.

END不匹配任何的输入文件,但是执行动作块中的所有动作,它在整个输入文件处理完成后被执行。如$ awk ‘END{print “The number of records is” NR}’ test,上式将打印所有被处理的记录数。

15.2 在这里,BEGIN预置了内部变量FS(字段分隔符)和自定义变量total,同时在扫描之前显示出输出行头。而END则在扫描完成后打印出总合计。

[root@localhost ~]# awk 'BEGIN { FS=":";print "统计销售金额";total=0} {print $3;total=total+$3;}{printf "销售金额总计:%.2f",total}' sx
统计销售金额
200.00
销售金额总计:200.00
销售金额总计:200.00300.00
销售金额总计:500.00
销售金额总计:500.00400.00
销售金额总计:900.00

 

猜你喜欢

转载自blog.csdn.net/a1779078902/article/details/81865638