标签(空格分隔): Linux 实战教学笔记 - 陈思齐
* | |||
---|---|---|---|
* | * | * | * |
* | * | * | * |
* | * | * | * |
* | * | * | * |
* | |||
---|---|---|---|
* | * | * | * |
* | * | * | * |
* | * | * | * |
* | * | * | * |
* | * | * | * |
* | * | * | * |
* | * | ||
* | * |
- [root@chensiqi1 ~]# cat /etc/redhat-release
- CentOS release 6.8 (Final)
- [root@chensiqi1 ~]# uname -r
- 2.6.32-642.el6.x86_64
- [root@chensiqi1 ~]# ll `which awk`
- lrwxrwxrwx. 1 root root 4 Dec 23 20:25 /bin/awk -> gawk
- [root@chensiqi1 ~]# awk --version
- GNU Awk 3.1.7
- Copyright (C) 1989, 1991-2009 Free Software Foundation.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
awk 处理的内容可以来自标准输入(<),一个或多个文本文件或管道。
示例 1-1: 基本的模式和动作
- [root@chensiqi1 ~]# awk -F ":" 'NR>=2 && NR<=6{print NR,$1}' /etc/passwd
- 2 bin
- 3 daemon
- 4 adm
- 5 lp
- 6 sync
- 命令说明:
- -F 指定分隔符为冒号,相当于以":"为菜刀,进行字段的切割。
- NR>=2 && NR<=6:这部分表示模式,是一个条件,表示取第2行到第6行。
- {print NR,$1}:这部分表示动作,表示要输出NR行号和$1第一列。
示例 1-2 只有模式
- [root@chensiqi1 ~]# awk -F ":" 'NR>=2&&NR<=6' /etc/passwd
- 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
- 命令说明:
- -F指定分隔符为冒号
- NR>=2&&NR<=6这部分是条件,表示取第2行到第6行。
- 但是这里没有动作,这里大家需要了解如果只有条件(模式)没有动作,awk默认输出整行
示例 1-3: 只有动作
- [root@chensiqi1 ~]# awk -F ":" '{print NR,$1}' /etc/passwd
- 1 root
- 2 bin
- 3 daemon
- 4 adm
- 5 lp
- 6 sync
- 7 shutdown
- 8 halt
- 9 mail
- 10 uucp
- 以下省略....
- 命令说明:
- -F指定分隔符为冒号
- 这里没有条件,表示对每一行都处理
- {print NR,$1}表示动作,显示NR行号与$1第一列
- 这里要理解没有条件的时候,awk会处理每一行。
示例 1-4: 多个模式和动作
- [root@chensiqi1 ~]# awk -F ":" 'NR==1{print NR,$1}NR==2{print NR,$NF}' /etc/passwd
- 1 root
- 2 /sbin/nologin
- 命令说明:
- -F指定分隔符为冒号
- 这里有多个条件与动作的组合
- NR==1表示条件,行号(NR)等于1的条件满足的时候,执行{print NR,$1}动作,输出行号与第一列。
- NR==2表示条件,行号(NR)等于2的条件满足的时候,执行{print NR,$NF}动作,输出行号与最后一列($NF)
注意:
示例 1-5 示例文件的创建
- [root@chensiqi1 ~]# mkdir /server/files/ -p
- [root@chensiqi1 ~]# head /etc/passwd > /server/files/awkfile.txt
- [root@chensiqi1 ~]# cat /server/files/awkfile.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
- uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
这个文件仅包含十行文件,我们使用下面的命令:
示例 1-6 awk 执行过程演示
- [root@chensiqi1 ~]# awk 'NR>=2{print $0}' /server/files/awkfile.txt
- 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
- 命令说明:
- 条件NR>=2,表示行号大于等于2时候,执行{print $0}显示整行。
- awk是通过一行一行的处理文件,这条命令中包含模式部分(条件)和动作部分(动作),awk将处理模式(条件)指定的行
1)awk 读入第一行内容
2)判断是否符合模式中的条件 NR>=2
a,如果匹配则执行对应的动作 {print $0}
b,如果不匹配条件,继续读取下一行
3)继续读取下一行
4)重复过程 1-3,直到读取到最后一行(EOF:end of file)
接下来我给大家带来两个新概念记录和字段,这里为了方便大家理解可以把记录就当作行即记录 == 行,字段相当于列,字段 == 列。
名称 | 含义 |
---|---|
record | 记录,行 |
field | 域,区域,字段,列 |
查看一下下面这段文字
- 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
思考:
一共有多少行呢?你如何知道的?通过什么标志?
awk 使用内置变量 RS 来存放输入记录分隔符,RS 表示的是输入的记录分隔符,这个值可以通过 BEGIN 模块重新定义修改。
示例 1-1:使用 "/" 为默认记录分隔符
示例文件:
- [root@chensiqi1 ~]# cat /server/files/awkfile.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
- uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
- [root@chensiqi1 ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /server/files/awkfile.txt
- 1 root:x:0:0:root:
- 2 root:
- 3 bin
- 4 bash
- bin:x:1:1:bin:
- 5 bin:
- 6 sbin
- 7 nologin
- daemon:x:2:2:daemon:
- 8 sbin:
- 9 sbin
- 10 nologin
- adm:x:3:4:adm:
- 11 var
- 12 adm:
- 13 sbin
- 14 nologin
- lp:x:4:7:lp:
- 15 var
- 16 spool
- 17 lpd:
- 18 sbin
- 19 nologin
- sync:x:5:0:sync:
- 20 sbin:
- 21 bin
- 22 sync
- shutdown:x:6:0:shutdown:
- 23 sbin:
- 24 sbin
- 25 shutdown
- halt:x:7:0:halt:
- 26 sbin:
- 27 sbin
- 28 halt
- mail:x:8:12:mail:
- 29 var
- 30 spool
- 31 mail:
- 32 sbin
- 33 nologin
- uucp:x:10:14:uucp:
- 34 var
- 35 spool
- 36 uucp:
- 37 sbin
- 38 nologin
- 命令说明:
- 在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。
- 我们设置RS(记录分隔符)的值为"/",表示一行(记录)以"/"结束
- 在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些\n(回车换行符),\n也是字符哦。
我们回顾下 "行(记录)" 到底是什么意思?
在工作中,我们可以通过修改 RS 变量的值来决定行的结束标志,最终来决定 "每行" 的内容。
为了方便人们理解,awk 默认就把 RS 的值设置为 "\n"
示例 1-2:NR 记录号
- [root@chensiqi1 ~]# awk '{print NR,$0}' /server/files/awkfile.txt
- 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
- 命令说明:
- NR既number of record,当前记录的记录号,刚开始学也可以理解为行号。
- $0表示整行或者说整个记录
注:(此处使用 sort 与 uniq 即可)
题目:
- [root@chensiqi1 files]# cat /server/files/count.txt
- root x root root bin bash
- bin x bin bin sbin nologin
- daemon x daemon sbin sbin nologin
- adm x adm var adm sbin nologin
- lp x lp var spool lpd sbin nologin
- sync x sync sbin bin sync
- shutdown x shutdown sbin sbin shutdown
- halt x halt sbin sbin halt
- mail x mail var spool mail sbin nologin
- uucp x uucp var spool uucp sbin nologin
思路:
让所有单词排成一列,这样每个单词都是单独的一行
1) 设置 RS 值为空格
2)将文件里面的所有空格替换为回车换行符 "\n"
3)grep 所有连续的字母,grep -o 参数让他们排成一列。
方法一:
- [root@chensiqi1 files]# awk 'BEGIN{RS="[ ]+"}{print $0}' count.txt | sort |uniq -c|sort
- 1
- 1 bash
- 1 lpd
- 2 daemon
- 2 lp
- 3 adm
- 3 halt
- 3 mail
- 3 root
- 3 shutdown
- 3 spool
- 3 sync
- 3 uucp
- 4 var
- 5 bin
- 6 nologin
- 10 x
- 12 sbin
方法二:
- [root@chensiqi1 files]# cat count.txt | tr " " "\n" | sort | uniq -c | sort
- 1 bash
- 1 lpd
- 2 daemon
- 2 lp
- 3 adm
- 3 halt
- 3 mail
- 3 root
- 3 shutdown
- 3 spool
- 3 sync
- 3 uucp
- 4 var
- 5 bin
- 6 nologin
- 10 x
- 12 sbin
方法三:
- [root@chensiqi1 files]# grep -o "[a-zA-Z]\+" count.txt | sort | uniq -c | sort
- 1 bash
- 1 lpd
- 2 daemon
- 2 lp
- 3 adm
- 3 halt
- 3 mail
- 3 root
- 3 shutdown
- 3 spool
- 3 sync
- 3 uucp
- 4 var
- 5 bin
- 6 nologin
- 10 x
- 12 sbin
OFS 输出字段(列)分隔符
下面我们通过示例来加强学习。
示例 1-3:指定分隔符
- [root@chensiqi1 files]# awk -F ":" 'NR>=2&&NR<=5{print $1,$3}' /server/files/awkfile.txt
- bin 1
- daemon 2
- adm 3
- lp 4
- 命令说明:
- 以:(冒号)为分隔符,显示第2行到第5行之间的第一区域和第三区域。
企业面试题:同时取出 chensiqi 和 215379068 这两个内容(指定多分隔符)
- [root@chensiqi1 files]# echo "I am chensiqi,my qq is 1234567890">>/server/files/chensiqi.txt
- [root@chensiqi1 files]# cat /server/files/chensiqi.txt
- I am chensiqi,my qq is 1234567890
同时取出 chensiqi 和 1234567890 这两个内容。
思路:
我们用默认的想法一次使用一把刀,需要配合管道的。如何同时使用两把刀呢?看下面的结果
- [root@chensiqi1 files]# awk -F "[ ,]" '{print $3,$NF}' /server/files/chensiqi.txt
- chensiqi 1234567890
- 命令说明:
- 通过命令-F参数指定区域分隔符
- [ ,]是正则表达式里面的内容,它表示一个整体,"一个"字符,既空格或者逗号(,),合并在一起,-F "[ ,]"就表示以空格或者逗号(,)为区域分隔符
示例:默认分隔符和指定分隔符会有些差异
- [root@chensiqi1 files]# ifconfig eth0 | awk 'NR==2' >/server/files/awkblank.txt
- [root@chensiqi1 files]# cat /server/files/awkblank.txt
- inet addr:192.168.197.133 Bcast:192.168.197.255 Mask:255.255.255.0
- #默认分隔符时候
- [root@chensiqi1 files]# awk '{print $1}' /server/files/awkblank.txt
- inet
- #指定分隔符时候
- [root@chensiqi1 files]# awk -F "[ :]+" '{print $1}' /server/files/awkblank.txt
- [root@chensiqi1 files]# awk -F "[ :]+" '{print $2}' /server/files/awkblank.txt
- inet
- 命令说明:
- awk默认的FS分隔符对于空格序列,一个空格或多个空格tab都认为是一样的,一个整体。
现在说说 ORS 和 OFS 这两个内置变量的含义。
现在你应该会对 awk 的记录字段有所了解了,下面我们总结一下,学会给阶段性知识总结是学好运维的必备技能。
- $符号表示取某个列(字段),$1$2$NF
取最后一个列(区域。)
- $NF
比较核心常用的是字段。
另外这些企业面试题可是学会 awk 的必备,必须自己也能写出来。
接下来就详细介绍下,awk 的模式都有几种:
awk 的模式是你玩好 awk 的必备也是最基础的内容,必须熟练掌握
awk 同 sed 一样也可以通过模式匹配来对输入的文本进行匹配处理。说到模式匹配,肯定少不了正则表达式,awk 也支持大量的正则表达式模式,大部分与 sed 支持的元字符类似,而且正则表达式是玩转三剑客的必备工具,下表列出了 awk 支持的正则表达式元字符:
awk 默认就支持的元字符:
元字符 | 功能 | 示例 | 解释 |
---|---|---|---|
^ | 字符串开头 | /^chensiqi / 或 \$3~/^chensiqi/ | 匹配所有以 chensiqi 开头的字符串;匹配出所有第三列中以 chensiqi 开头的 |
\$ | 字符串结尾 | /chensiqi$/ 或 $3~/chensiqi$/ | 匹配所有以 chensiqi 结尾的字符串;匹配第三列中以 chensiqi 结尾的 |
.(点) | 匹配任意但个字符(包括回车符) | /c..l/ | 匹配字母 c,然后两个任意字符,再以 l 结尾的行 |
* | 重复 0 个或多个前一个字符 | /a*cool/ | 匹配 0 个或多个 a 之后紧跟着 cool 的行 |
+ | 重复前一个字符一次或多次 | /a+b/ | 匹配一个或多个 a 加上字符串 b 的行 |
? | 匹配 0 个或一个前边的字符 | /a?b/ | 匹配以字母 a 或 b 或 c 开头的行 |
[] | 匹配指定字符组内的任一个字符 | /^[abc]/ | 匹配以字母 a 或 b 或 c 开头的行 |
[^] | 匹配不在指定字符组内的任一字符 | /^[^abc]/ | 匹配不以字母 a 或 b 或 c 开头的行 |
() | 子表达式组合 | /(chensiqi)+/ | 表示一个或多个 cool 组合,当有一些字符需要组合时,使用括号括起来 |
\ | 或者的意思 | /(chensiqi)\ |
awk 默认不支持的元字符:(参数 --posix)
元字符 | 功能 | 示例 | 解释 |
---|---|---|---|
x{m} | x 字符重复 m 次 | /cool{5}/ | 匹配 l 字符 5 次 |
x{m,} | x 字符重复至少 m 次 | /(cool){2,}/ | 匹配 cool 整体,至少 2 次 |
x{m,n} | x 字符重复至少 m 次,但不超过 n 次 | /(cool){5,6}/ | 匹配 cool 整体,至少 5 次,最多 6 次 |
提示:
awk 正则匹配操作符:
|~| 用于对记录或区域的表达式进行匹配 |
|--|--|
|!~| 用于表达与~相反的意思 |
下面还是通过具体示例来看看,awk 如何来通过正则表达式匹配字符串的
- [root@chensiqi1 files]# awk -F ":" '/^root/' awkfile.txt
- root:x:0:0:root:/root:/bin/bash
和下面的效果是一样的
- [root@chensiqi1 files]# awk -F ":" '$0~/^root/' awkfile.txt
- root:x:0:0:root:/root:/bin/bash
提示:
awk 只用正则表达式的时候是默认匹配整行的即'$0~/^root/'和'/^root/'是一样的。
- [root@chensiqi1 files]# awk -F ":" '$5~/shutdown/' awkfile.txt
- shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
提示:
合并在一起
$5~/shutdown / 表示第五个区域(列)匹配正则表达式 / shutdown/,既第 5 列包含 shutdown 这个字符串,则显示这一行。
知道了如何使用正则表达式匹配操作符之后,我们来看看 awk 正则与 grep 和 sed 不同的地方。
awk 正则表达式
|^| 匹配一个字符串的开头 |
|--|--|
|$| 匹配一个字符串的结尾 |
在 sed 和 grep 这两个命令中,我们都把它们当作行的开头和结尾。但是在 awk 中他表示的是字符串的开头和结尾。
接下来我们通过练习题来联系 awk 如何使用正则表达式。
- [root@chensiqi1 ~]# cat >>/server/files/reg.txt<<KOF
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- KOF
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
说明:
练习题 1: 显示姓 Zhang 的人的第二次捐款金额及她的名字
练习题 2: 显示 Xiaoyu 的名字和 ID 号码
练习题 3: 显示所有以 41 开头的 ID 号码的人的全名和 ID 号码
练习题 4: 显示所有以一个 D 或 X 开头的人名全名
练习题 5: 显示所有 ID 号码最后一位数字是 1 或 5 的人的全名
练习题 6: 显示 Xiaoyu 的捐款,每个值都有以 $ 开头。如 $520$200$135
练习题 7: 显示所有人的全名,以姓,名的格式显示,如 Meng,Feixue
示例 1: 显示姓 Zhang 的人的第二次捐款金额及她的名字
- [root@chensiqi1 files]# cat reg.txt
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- [root@chensiqi1 files]# awk -F "[ :]+" '$1~/^Zhang/{print $2,$(NF-1)}' reg.txt
- Zhang 100
- Zhang 90
说明:
注意:
NF 是一行中有多少列,NF-1 整行就是倒数第二列。
$(NF-1) 就是取倒数第二列内容。
示例 2: 显示 Xiaoyu 的姓氏和 ID 号码
- [root@chensiqi1 files]#cat reg.txt
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- [root@chensiqi1 files]# awk -F "[ :]+" '$2~/^Xiaoyu/{print $1,$3}' reg.txt
- Zhang 390320151
- 命令说明:
- 指定分隔符-F "【:】+"
- $2~/Xiaoyu/表示条件,第二列包含Xiaoyu时候执行对应的动作
- {print $1,$3}表示动作,显示第一列和第三列的内容
示例 3: 显示所有以 41 开头的 ID 号码的人的全名和 ID 号码
- [root@chensiqi1 files]# cat reg.txt
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- [root@chensiqi1 files]# awk -F "[ :]+" '$3~/^(41)/{print $1,$2,$3}' reg.txt
- Zhang Dandan 41117397
- Liu Bingbing 41117483
示例 4: 显示所有以一个 D 或 X 开头的人名全名
- [root@chensiqi1 files]# cat reg.txt
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- [root@chensiqi1 files]# awk -F "[ :]+" '$2~/^D|^X/{print $1,$2}' reg.txt
- Zhang Dandan
- Zhang Xiaoyu
- Wang Xiaoai
- 命令说明:
- -F "【 :】+"指定分隔符
- |表示或,^以...开头
注意:
这里要用()括号表示即 ^(D|X) 相当于 ^D|^X,有的同学写成 ^D|X 这样是错误的。
示例 5: 显示所有 ID 号码最后一位数字是 1 或 5 的人的全名
- [root@chensiqi1 files]# cat reg.txt
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- [root@chensiqi1 files]# awk -F "[ :]+" '$3~/1$|5$/{print $1,$2}' reg.txt
- Zhang Xiaoyu
- Wu Waiwai
- Wang Xiaoai
- Li Youjiu
- Lao Nanhai
示例 6: 显示 Xiaoyu 的捐款,每个值都有以 $ 开头。
- 如$520$200$135
- [root@chensiqi1 files]# cat reg.txt
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- [root@chensiqi1 files]# awk -F "[ :]+" '$2~/Xiaoyu/{print "$"$4"$"$5"$"$6}' reg.txt
- $155$90$201
示例 7: 显示所有人的全名,以姓,名的格式显示,如 Meng,Feixue
- [root@chensiqi1 files]# cat reg.txt
- Zhang Dandan 41117397 :250:100:175
- Zhang Xiaoyu 390320151 :155:90:201
- Meng Feixue 80042789 :250:60:50
- Wu Waiwai 70271111 :250:80:75
- Liu Bingbing 41117483 :250:100:175
- Wang Xiaoai 3515064655 :50:95:135
- Zi Gege 1986787350 :250:168:200
- Li Youjiu 918391635 :175:75:300
- Lao Nanhai 918391635 :250:100:175
- [root@chensiqi1 files]# awk -F "[ ]+" '{print $1","$2}' reg.txt
- Zhang,Dandan
- Zhang,Xiaoyu
- Meng,Feixue
- Wu,Waiwai
- Liu,Bingbing
- Wang,Xiaoai
- Zi,Gege
- Li,Youjiu
- Lao,Nanhai
最简单:hostname -I
awk 处理:
方法一:
- [root@chensiqi1 files]# ifconfig eth0|awk 'BEGIN{RS="[ :]"}NR==31'
- 192.168.197.133
方法二:
- [root@chensiqi1 files]# ifconfig eth0 | awk -F "(addr:)|( Bcast:)" 'NR==2{print $2}'
- 192.168.197.133
方法三:
- [root@chensiqi1 files]# ifconfig eth0 | awk -F "[ :]+" 'NR==2{print $4}'
- 192.168.197.133
方法四:
- [root@chensiqi1 files]# ifconfig eth0 | awk -F "[^0-9.]+" 'NR==2{print $2}'
- 192.168.197.133
提示:
- [root@chensiqi1 files]# echo "------======1########2"
- ------======1########2
- [root@chensiqi1 files]# echo "------======1########2" | grep "[-=#]"
- ------======1########2
- [root@chensiqi1 files]# echo "------======1########2" | grep -o "[-=#]"
- -
- -
- -
- -
- -
- -
- =
- =
- =
- =
- =
- =
- #
- #
- #
- #
- #
- #
- #
- #
awk 中的花括号有些不常用,但是偶尔会用到这里简单介绍。
示例:取出 awkfile 中第一列包含一个 o 或者两个 o 的行
- [root@chensiqi1 files]# awk -F: '$1~/o{1,2}/' awkfile.txt
- [root@chensiqi1 files]# awk -F: --posix '$1~/o{1,2}/' awkfile.txt
- root:x:0:0:root:/root:/bin/bash
- daemon:x:2:2:daemon:/sbin:/sbin/nologin
- shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
- [root@chensiqi1 files]# awk -F: --re-interval '$1~/o{1,2}/' awkfile.txt
- root:x:0:0:root:/root:/bin/bash
- daemon:x:2:2:daemon:/sbin:/sbin/nologin
- shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
思路:
linux 下面服务与端口信息的对应表格在 / etc/services 里面,所以这道题要处理 / etc/services 文件。
我们简单分析以下 servics 文件:
- [root@chensiqi1 ~]# sed -n '23,30p' /etc/services
- tcpmux 1/tcp # TCP port service multiplexer
- tcpmux 1/udp # TCP port service multiplexer
- rje 5/tcp # Remote Job Entry
- rje 5/udp # Remote Job Entry
- echo 7/tcp
- echo 7/udp
- discard 9/tcp sink null
- discard 9/udp sink null
从 23 行开始基本上每一行第一列是服务名称,第二列的第一部分是端口号,第二列的第二部分是 tcp 或 udp 协议。
方法:
- [root@chensiqi1 ~]# awk -F "[ /]+" '$1~/^(ssh)$|^(http)$|^(https)$|^(mysql)$|^(ftp)$/{print $1,$2}' /etc/services |sort|uniq
- ftp 21
- http 80
- https 443
- mysql 3306
- ssh 22
提示:
awk 是一种编程语言,能够进行更为复杂的判断,当条件为真时候,awk 就执行相关的 action。主要是针对某一区域做出相关的判断,比如打印成绩在 80 分以上的行,这样就必须对这一区域做比较判断,下表列出了 awk 可以使用的关系运算符,可以用来比较数字字符串,还有正则表达式。当表达式为真时候,表达式结果 1,否 0,只有表达式为真,awk 才执行相关的 action
运算符 | 含义 | 示例 |
---|---|---|
< | 小于 | x>y |
<= | 小于等于 | x<=y |
== | 等于 | x==y |
!= | 不等于 | x!=y |
>= | 大于或等于 | x>=y |
> | 大于 | x<y |
以上运算符是针对数字的,下面两个运算符之前已有示例,针对字符串
~ | 与正则表达式匹配 | x~/y/ |
---|---|---|
!~ | 与正则表达式不匹配 | x!~y |
思路:
想表示一个范围,一个行的范围,就要用到 NR 这个内置变量了,同时也要用到比较表达式。
答案:
- [root@www ~]# awk 'NR>=23&&NR<=30' /etc/services
- [root@www ~]# awk 'NR>22&&NR<31' /etc/services
过程:
- [root@www ~]# awk 'NR>=23&&NR<=30' /etc/services
- tcpmux 1/tcp # TCP port service multiplexer
- tcpmux 1/udp # TCP port service multiplexer
- rje 5/tcp # Remote Job Entry
- rje 5/udp # Remote Job Entry
- echo 7/tcp
- echo 7/udp
- discard 9/tcp sink null
- discard 9/udp sink null
- [root@www ~]# awk 'NR>22&&NR<31' /etc/services
- tcpmux 1/tcp # TCP port service multiplexer
- tcpmux 1/udp # TCP port service multiplexer
- rje 5/tcp # Remote Job Entry
- rje 5/udp # Remote Job Entry
- echo 7/tcp
- echo 7/udp
- discard 9/tcp sink null
- discard 9/udp sink null
说明:
1)比较表达式比较常用的还是表示大于等于,小于等于或者等于,根据这个例子来学习即可
2)NR 表示行号,大于等于 23 即,NR>=23 小于等于 30,即 NR<=30
3) 合起来就是 NR>=23 并且 NR<=30,&& 表示并且,同时成立的意思。
4)换一种表达式方法就是大于 22 行小于 31 行,即 NR>22&&NR<31
示例:找出 / etc/passwd 中第五列是 root 的行
测试文件:
- [root@www ~]# cat /server/files/awk_equal.txt
- root:x:0:0:root:/root:/bin/bash
- root:x:0:0:rootroot:/root:/bin/bash
- root:x:0:0:rootrooot:/root:/bin/bash
- root:x:0:0:rootrooot:/root:/bin/bash
- root:x:0:0:/root:/bin/bash
答案:
- awk -F":" '$5=="root"' /server/files/awk_equal.txt
- awk -F":" '$5~/^root$/' /server/files/awk_equal.txt
过程:
- #方法一:
- [root@www ~]# awk -F":" '$5=="root"' /server/files/awk_equal.txt
- root:x:0:0:root:/root:/bin/bash
- #方法二:
- [root@www ~]# awk -F":" '$5~/^root$/' /server/files/awk_equal.txt
- root:x:0:0:root:/root:/bin/bash
我们如果想要完全匹配 root 这个字符串,那就用
即可,这也是答案里面给大家的。
- $5=="root"
方法二:
此题也可通过正则匹配来限制 root 的字符串。
- $5~/^root$/
pattern1 | pattern2 | |
---|---|---|
从哪里来 | 到 | 哪里去 |
条件 1 | 条件 2 |
- awk '/start pos/,/end pos/{print $)} passwd chensiqi'
- awk '/start pos/,NR==XXX{print $0}' passwd chensiqi
范围模式的时候,范围条件的时候,表达式必须能匹配一行。
示例 1:
- [root@www files]# awk 'NR==2,NR==5{print NR,$0}' count.txt
- 2 bin x bin bin sbin nologin
- 3 daemon x daemon sbin sbin nologin
- 4 adm x adm var adm sbin nologin
- 5 lp x lp var spool lpd sbin nologin
说明:
条件是:从第二行,到第五行
动作是:显示行号(NR)和整行($0)
合起来就是显示第二行到第五行的行好和整行的内容
示例 2:
- [root@www files]# awk '/^bin/,NR==5{print NR,$0}' awkfile.txt
- 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
说明:
条件是:从以 bin 开头的行,到第五行
动作是:显示行号和整行内容
合起来就是显示从以 bin 开头的行,到第五行中的行号和整行内容。
示例 3:
- [root@www files]# awk -F":" '$5~/^bin/,/^lp/{print NR,$0}' awkfile.txt
- 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
说明:
条件:从第五列以 bin 开头的行到以 lp 开头的行
动作:显示行号和正航内容
合起来:从第三列以 bin 开始的行到以 lp 开头的行并显示其行号和整行内容
- [root@www files]# awk -F: '$5~/^bin/,$5~/^lp/{print NR,$0}' awkfile.txt
- 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
说明:
条件:从第三列以 bin 开头字符串的行到第三列以 lp 开头字符串的行
动作:显示行号和整行
1)第一个作用,内置变量的定义
示例:取 eth0 的 IP 地址
答案:
- [root@www files]# ifconfig eth0|awk -F "(addr:)|( Bcast:)" 'NR==2{print $2}'
- 192.168.197.133
- [root@www files]# ifconfig eth0 | awk -F "[ :]+" 'NR==2{print $4}'
- 192.168.197.133
- [root@www files]# ifconfig eth0 | awk -F "[^0-9.]+" 'NR==2{print $2}'
- 192.168.197.133
- #上面的也可以写成
- [root@www files]# ifconfig eth0 | awk 'BEGIN{FS="(addr:)|( Bcast:)"} NR==2{print $2}'
- 192.168.197.133
- [root@www files]# ifconfig eth0 | awk 'BEGIN{FS="[ :]+"}NR==2{print $4}'
- 192.168.197.133
- [root@www files]# ifconfig eth0 | awk 'BEGIN{FS="[^0-9.]+"}NR==2{print $2}'
- 192.168.197.133
注意:
命令行 - F 本质就是修改的 FS 变量
2)第二个作用,在读取文件之前,输出些提示性信息(表头)。
- [root@www files]# awk -F: 'BEGIN{print "username","UID"}{print $1,$3}' awkfile.txt
- username UID #这就是输出的表头信息
- root 0
- bin 1
- daemon 2
- adm 3
- lp 4
- sync 5
- shutdown 6
- halt 7
- mail 8
- uucp 10
说明:
要在第一行输出一些 username 和 UID,我们应该想到 BEGIN{} 这个特殊的条件(模式),因为 BEGIN{} 在 awk 读取文件之前执行的。
所以结果是
, 注意 print 命令里面双引号吃啥吐啥,原样输出。
- BEGIN{print "username","UID"}
最后结果就是
- {print $1,$3}
- BEGIN{print "username","UID"}{print $1,$3}
3) 第三个作用,使用 BEGIN 模块的特殊性质,进行一些测试。
- [root@www files]#简单输出内容:
- [root@www files]# awk 'BEGIN{print "hello world!"}'
- hello world!
- [root@www files]# #进行计算
- [root@www files]# awk 'BEGIN{print 10/3}'
- 3.33333
- [root@www files]# awk 'BEGIN{print 10/3+1}'
- 4.33333
- [root@www files]# awk 'BEGIN{print 10/3+1/4*9}'
- 5.58333
- [root@www files]# #和变量有关的操作
- [root@www files]# awk 'BEGIN{a=1;b=2;print a,b}'
- 1 2
- [root@www files]# awk 'BEGIN{a=1;b=2;print a,b,a+b}'
- 1 2 3
4)第四种用法:配合 getline 读取文件,后面 awk 函数处讲解
- [root@chensiqi files]# awk 'BEGIN{a=abcd;print a}'
- [root@chensiqi files]# awk 'BEGIN{abcd=123456;a=abcd;print a}'
- 123456
- [root@chensiqi files]# awk 'BEGIN{a="abcd";print a}'
- abcd
说明:
没有文件 awk 依旧可以处理 BEGIN 模式下的动作(命令)
EHD 在 awk 读取完所有的文件的时候,再执行 END 模块,一般用来输出一个结果(累加,数组结果),也可以是和 BEGIN 模块类似的结尾标识信息
- [root@chensiqi files]# awk 'BEGIN{print "hello world!"}{print NR,$0}END{print "end of file"}' count.txt
- hello world!
- 1 root x root root bin bash
- 2 bin x bin bin sbin nologin
- 3 daemon x daemon sbin sbin nologin
- 4 adm x adm var adm sbin nologin
- 5 lp x lp var spool lpd sbin nologin
- 6 sync x sync sbin bin sync
- 7 shutdown x shutdown sbin sbin shutdown
- 8 halt x halt sbin sbin halt
- 9 mail x mail var spool mail sbin nologin
- 10 uucp x uucp var spool uucp sbin nologin
- end of file
与 BEGIN 模式相对应的 END 模式,格式一样,但是 END 模式仅在 awk 处理完所有输入行后才进行处理。
企业案例:统计 / etc/servies 文件里的空行数量
思路:
a) 空行通过正则表达式来实现:^$
b) 统计数量:
方法一:grep
- [root@chensiqi files]# grep "^$" /etc/services | wc -l
- 16
- [root@chensiqi files]# grep -c "^$" /etc/services
- 16
- 说明:
- grep命令-c表示count计数统计包含^$的行一共有多少。
方法二:
- [root@chensiqi files]# awk '/^$/{i++}END{print i}' /etc/services
- 16
提示:
使用了 awk 的技术功能,很常用
第一步:统计空行个数
表示条件,匹配出空行,然后执行 {i++}(i++ 等于 i=i+1) 即:
- /^$/
- /^$/{i=i+1}
我们可以通过
来查看 awk 执行过程
- /^$/{i=i+1;print i}
- [root@chensiqi files]# awk '/^$/{i=i+1;print "the value of i is:"i}' /etc/services
- the value of i is:1
- the value of i is:2
- the value of i is:3
- the value of i is:4
- the value of i is:5
- the value of i is:6
- the value of i is:7
- the value of i is:8
- the value of i is:9
- the value of i is:10
- the value of i is:11
- the value of i is:12
- the value of i is:13
- the value of i is:14
- the value of i is:15
- the value of i is:16
第二步:输出最后结果
所以最终结果就是
- awk '/^$/{i=i+1}END{print "blank lines count:"i}' /etc/services
awk 编程思想:
模块处理,处理完毕后
- {print NR,$0}body
输出一个结果
- END{print "end of file"}
企业面试题 5:文件 count.txt, 文件内容是 1 到 100(由 seq 100 生成),请计算文件每行值加起来的结果(计算 1+...+100)
思路:
文件每一行都有且只有一个数字,所以我们要让文件的每行内容相加。
回顾一下上一道题我们用的是 i++ 即 i=i+1
这里我们需要使用到第二个常用的表达式
i=i+$0
对比一下,其实只是把上边的 1 换成了 $0
- [root@chensiqi files]# awk '{i=i+$0}END{print i}' count.txt
- 5050
回顾一下 awk 的结构
awk -F 指定分隔符'BRGIN{}END{}',如下图
- #awk完整执行过程
- [root@chensiqi ~]# awk -F ":" 'BEGIN{RS="/";print "hello world!"}{print NR,$0}END{print "end of file"}' /server/files/awkfile.txt
- hello world!
- 1 root:x:0:0:root:
- 2 root:
- 3 bin
- 4 bash
- bin:x:1:1:bin:
- 5 bin:
- 6 sbin
- 7 nologin
- daemon:x:2:2:daemon:
- 8 sbin:
- 9 sbin
- 10 nologin
- adm:x:3:4:adm:
- 11 var
- 12 adm:
- 13 sbin
- 14 nologin
- lp:x:4:7:lp:
- 15 var
- 16 spool
- 17 lpd:
- 18 sbin
- 19 nologin
- sync:x:5:0:sync:
- 20 sbin:
- 21 bin
- 22 sync
- shutdown:x:6:0:shutdown:
- 23 sbin:
- 24 sbin
- 25 shutdown
- halt:x:7:0:halt:
- 26 sbin:
- 27 sbin
- 28 halt
- mail:x:8:12:mail:
- 29 var
- 30 spool
- 31 mail:
- 32 sbin
- 33 nologin
- uucp:x:10:14:uucp:
- 34 var
- 35 spool
- 36 uucp:
- 37 sbin
- 38 nologin
- end of file
说明:
我们 · 同时再命令行定义了分隔符和在 BEGIN 模式中定义了 RS 内置变量,在最后通过 END 模式输出了结果
awk 提供了数组来存放一组相关的值。
awk 是一种编程语言,肯定也支持数组的运用,但是又不同于 c 语言的数组。数组在 awk 中被称为关联数组,因为它的下标既可以是数字也可以是字符串。下标通常被称作 key,并且与对应的数组元素的值关联。数组元素的 key 和值都存储在 awk 程序内部的一张表中,通过一定散列算法来存储,所以数组元素都不是按顺序存储的。打印出来的顺序也肯定不是按照一定的顺序,但是我们可以通过管道来对所需的数据再次操作来达到自己的效果。
如图不难发现,awk 数组就和酒店一样。数组的名称就像是酒店名称,数组元素名称就像酒店房间号码,每个数组元素里面的内容就像是酒店房间里面的人。
假设我们有一个酒店
- 酒店<===>chensiqihotel
酒店里面有几个房间 110,119,120,114 这几个房间
- 酒店110房间<===>chensiqihotel[110]
- 酒店120房间<===>chensiqihotel[120]
- 酒店119房间<===>chensiqihotel[119]
- 酒店114房间<===>chensiqihotel[114]
酒店房间里面入住客人
- 酒店110房间住着xiaoyu<===>chensiqihotel[110]="xiaoyu"
- 酒店119房间住着ruxue<===>chensiqihotel[119]="ruxue"
- 酒店120房间住着dandan<===>chensiqihotel[120]="dandan"
- 酒店114房间住着waiwai<===>chensiqihotel[114]="waiwai"
示例:
- [root@chensiqi ~]# awk 'BEGIN{chensiqihotel[110]="xiaoyu";chensiqihotel[119]="ruxue";chensiqihotel[120]="dandan";chensiqihotel[114]="waiwai";print chensiqihotel[110],chensiqihotel[119],chensiqihotel[120],chensiqihotel[114]}'
- xiaoyu ruxue dandan waiwai
- [root@chensiqi ~]# awk 'BEGIN{chensiqihotel[110]="xiaoyu";chensiqihotel[119]="ruxue";chensiqihotel[120]="dandan";chensiqihotel[114]="waiwai";for(hotel in chensiqihotel)print hotel,chensiqihotel[hotel]}'
- 110 xiaoyu
- 120 dandan
- 114 waiwai
- 119 ruxue
企业面试题 1: 统计域名访问次数
处理以下文件内容,将域名取出并根据域名进行计数排序处理:(百度和 sohu 面试题)
- http: //www.etiantian.org/index.html
- http: //www.etiantian.org/1.html
- http: //post.etiantian.org/index.html
- http: //mp3.etiantian.org/index.html
- http: //www.etiantian.org/3.html
- http: //post.etiantian.org/2.html
思路:
1)以斜线为菜刀取出第二列(域名)
2)创建一个数组
3)把第二列(域名)作为数组的下标
4)通过类似于 i++ 的形式进行计数
5)统计后把结果输出
过程演示:
第一步:查看一下内容
- [root@chensiqi ~]# awk -F "[/]+" '{print $2}' file
- www.etiantian.org
- www.etiantian.org
- post.etiantian.org
- mp3.etiantian.org
- www.etiantian.org
- post.etiantian.org
- 命令说明:
- 这是我们需要计数的内容
第二步:计数
- [root@chensiqi ~]# awk -F "[/]+" '{i++;print $2,i}' file
- www.etiantian.org 1
- www.etiantian.org 2
- post.etiantian.org 3
- mp3.etiantian.org 4
- www.etiantian.org 5
- post.etiantian.org 6
- 命令说明:
- i++:i最开始是空的,当awk读取一行,i自身+1
第三步:用数组替换 i
- [root@chensiqi ~]# awk -F "[/]+" '{h[$2]++;print $2,h["www.etiantian.org"]}' file
- www.etiantian.org 1
- www.etiantian.org 2
- post.etiantian.org 2
- mp3.etiantian.org 2
- www.etiantian.org 3
- post.etiantian.org 3
- 命令说明:
- 1)将i替换成h[$2];相当于我创建了一个数组h[],然后用$2作为我的房间号。但是目前房间里是没有东西的。也就是说h[$2]=h["www.etiantian.org"] and h["post.etiantian.org"] and h["mp3.etiantian.org"] 但是具体房间里是没有东西的也就是空。
- 2)h[$2]++就等于i++:也就是说我开始给房间里加东西;当出现同样的东西,我就++
- 3)print h["www.etiantian.org"]:意思就是说我开始要输出了。我要输出的是房间号为"www.etiantian.org"里面的内容。这里面的内容最早是空的,随着awk读取每一行一旦出现房间号为"www.etiantian.org"的房间时,我就给房间里的内容进行++。
- 4)综上,输出的结果中,每次出现www.etiantian.org时,h["www.etiantian.org"]就会++。因此最后的输出数字是3
第四步:输出最终计数结果
- [root@chensiqi ~]# awk -F "[/]+" '{h[$2]++}END{for(i in h)print i,h[i]}' file
- mp3.etiantian.org 1
- post.etiantian.org 2
- www.etiantian.org 3
- [root@chensiqi ~]#
- 命令说明:
- 我们最终需要输出的是去重复以后的统计结果,所以得在END模块里进行输出
- for(i in h)遍历这个数组,i里存的都是房间号
- print i,h[i]:输出每一个房间号及其房间里的内容(计数结果)
提示:
awk 的应用里最重要的一个功能就是计数,而数组在 awk 里最大的作用就是去重复。请同学们仔细理解,多动手试验一下。
来源: http://www.cnblogs.com/chensiqiqi/p/6481647.html