grep 命令主要对文本的(正则表达式)行基于模式进行过滤
sed:stream editor,文本编辑工具
awk:Linux上的实现gawk,文本报告生成器
一、文本处理三剑客之 grep
grep: Global search REgular expression and Print out the line
作用:文本搜索工具,根据用户指定的“模式”对目标文本逐行进行匹配检查;打印匹配到的行
模式:由正则表达式字符及文本字符所编写的过滤条件
格式:
grep [OPTIONS] PATTERN [FILE...]
选项 | 说明 |
---|---|
--color=auto | 对匹配到的文本着色显示 |
-m # | 匹配#次后停止 |
-v | 显示不被pattern匹配到的行 |
-i | 忽略字符大小写 |
-n | 显示匹配的行号 |
-c | 统计匹配的行数 |
-o | 仅显示匹配到的字符串 |
-q | 静默模式,不输出任何信息 |
-A # after | 后#行 |
-B # before | 前#行 |
-C # context | 前后各#行 |
-e | 实现多个选项间的逻辑or关系,如:grep –e ‘cat ’ -e ‘dog’ file |
-w | 匹配整个单词 |
-E | 使用ERE,相当于egrep |
-F | 相当于fgrep,不支持正则表达式 |
-f | file 根据模式文件处理 |
-r | 递归目录,但不处理软链接 |
-R | 递归目录,但处理软链接 |
规则表达式
^ # 锚定行的开始 如:'^grep'匹配所有以grep开头的行。
$ # 锚定行的结束 如:'grep$' 匹配所有以grep结尾的行。
. # 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。
* # 匹配零个或多个先前字符 如:'*grep'匹配所有一个或多个空格后紧跟grep的行。
.* # 一起用代表任意字符。
[] # 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。
[^] # 匹配一个不在指定范围内的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。
\(..\) # 标记匹配字符,如'\(love\)',love被标记为1。
\< # 锚定单词的开始,如:'\<grep'匹配包含以grep开头的单词的行。
\> # 锚定单词的结束,如'grep\>'匹配包含以grep结尾的单词的行。
x\{m\} # 重复字符x,m次,如:'0\{5\}'匹配包含5个o的行。
x\{m,\} # 重复字符x,至少m次,如:'o\{5,\}'匹配至少有5个o的行。
x\{m,n\} # 重复字符x,至少m次,不多于n次,如:'o\{5,10\}'匹配5--10个o的行。
\w # 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\w*p'匹配以G后跟零个或多个文字或数字字符,然后是p。
\W # \w的反置形式,匹配一个或多个非单词字符,如点号句号等。
\b # 单词锁定符,如: '\bgrep\b'只匹配grep。
范例:
1、统计某文件夹下文件的个数
ls -l /data|grep "^-"|wc -l #不包含子目录
ls -lR /data|grep "^-"|wc -l #不含子目录
2、统计某文件夹下目录的个数
ls -l /data |grep "^d"|wc -l #不包含子目录
ls -lR /data|grep "^d"|wc -l #包含子目录
3、统计某目录(包含子目录)下的所有某种类型的文件
ls -lR /data|grep txt|wc -l
4、去除文本中的空行
grep -v '^\s*$' test.txt
5、多关键词匹配
grep pattern1 | pattern2 files :显示匹配 pattern1 或 pattern2 的
grep pattern1 files | grep pattern2 :显示既匹配 pattern1 又匹配 pattern2 的行。
grep -E '关键词1|关键词2'
6、xargs配合grep查找
find -type f -name '*.php'|xargs grep 'GroupRecord'
7、查找路径下含有某字符串的所有文件
grep -rn "hello,world!" *
8、完全匹配关键词
grep -Fx 关键词
9、精准匹配
grep -w 关键词
# 不加-w是默认情况
10、显示文件非#注释内容
# 显示文件非#注释内容
grep -v ^[[:space:]]*# 文本文件
# # 显示文件非#注释内容,不显示空行
egrep -v '#|^$' filename
11、删除空行并重定向到新文件
grep . filename > newfilename
二、文本处理三剑客之 sed
1、sed 工作原理
sed 即 stream EDitor,和 vi 不同,sed是行编辑器
Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行。每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间(Pattern Space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。如果使用vi命令打开几十M上百M的文件,明显会出现有卡顿的现象,这是因为vi命令打开文件是一次性将文件加载到内存,然后再打开。Sed就避免了这种情况,一行一行的处理,打开速度非常快,执行速度也很快
参考网站:https://www.gnu.org/software/sed/manual/sed.html
2、sed 基本用法
格式:
sed [-hnV][-e<script>][-f<script文件>][文本文件]
选项 | 说明 |
---|---|
-n或 --quiet或--silent | 仅显示script处理后的结果 |
-e <script> 或 --expression=<script> | 以选项中指定的script来处理输入的文本文件 |
-f <script文件> 或 --file=<script文件> | 以选项中指定的script文件来处理输入的文本文件 |
-r, -E | 使用扩展正则表达式 |
-i.bak | 备份文件并原处编辑 |
-h 或 --help | 显示帮助 |
动作说明
- a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)
- c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
- d :删除,因为是删除啊,所以 d 后面通常不接任何东西;
- i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行)
- p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行
- s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g
1、替换环境变量的值到文件中
如果想替换字符串中的值为环境变量的值,可以使用将匹配规则使用""
括起来,在""
中直接引用环境变量
echo "test asdasdas \$TEST" > test.txt
export aaaaa=1234
sed -i -e "s/\$TEST/$aaaaa/g" test.txt
如果变量的值中包含特殊字符,例如/
,与sed匹配模式的关键字符造成歧义。可使用?
代替/
echo "test asdasdas \$TEST" > test.txt
export aaaaa=/1234
sed -i "s?\$TEST?$aaaaa?g" test.txt
2、新增内容到末尾行的末尾
sed '$ s/$/新增内容/' file_path
3、去除文本中空行和开头"##"的行
sed '/^$/d;/^##/d' file_path
4、去除文本中的空行
sed '/^\s*$/d' test.txt
5、多个匹配规则
sed -i -e '/hah/a lala\nhehe' -e '/lala/d' test
6、在查找到匹配行后的操作
sed -i '/hah/a lallalla' test #在查找到匹配行后添加一行
sed -i '/hah/a lala\nhehe' test #在查找到匹配行后添加多行
sed -i '/hah/d' test #删除查找到匹配行
7、在查找匹配行的末首或末尾添加内容
sed -i '/ha/ s/^/la' test #在查找包含"ha"的行首追加"la","laha"
sed -i '/ha/ s/$/la' test #在查找包含"ha"的行末追加"la","hala"
8、去掉文本中开头带#号注释的行
sed -i -c -e '/^$/d;/^#/d' file
9、去除文本中的换行符^M
Windows下保存的文本文件,上传到Linux/Unix下后总会在末尾多了一个换行符^M,导致一些xml、ini、sh等文件读取错误
sed 's/^M//' 原文件>新文件
# 注意,^M = Ctrl v + Ctrl m,而不是手动输入^M
10、每行前后添加空行
每行后面添加一行空行:
sed G tmp
每行前面添加一行空行:
sed '{x;p;x;}' tmp
每行后面添加两行空行:
sed 'G;G' tmp
每行前面添加两行空行:
sed '{x;p;x;x;p;x;}' tmp
每行后面添加三行空行:
sed 'G;G;G' tmp
每行前面添加三行空行:
sed '{x;p;x;x;p;x;x;p;x}' tmp
依次类推,添加几行空行,就有几个G或者x;p;x
11、如果行后有空行,则删除,然后每行后面添加空行
sed '/^$/d;G' tmp
12、在匹配行前后添加空行
如果一行里面有shui这个单词,那么在他后面会添加一个空行
sed '/shui/G' tmp
如果一行里面有shui这个单词,那么在他前后各添加一个空行
sed '/shui/{x;p;x;G}' tmp
如果一行里面有shui这个单词,那么在他前面添加一个空行
sed '/shui/{x;p;x;}' tmp
在第一行前面添加空行,想在第几行,命令中的1就改成几
sed '1{x;p;x;}' tmp
在第一行后面添加空行,想在第几行,命令中的1就改成几
sed '1G' tmp
13、每几行后面添加一个空行
每两行后面增加一个空行
sed 'N;/^$/d;G' file.txt
每两行前面添加一个空行
sed 'N;/^$/d;{x;p;x;}' tmp
每三行后面增加一个空行
sed 'N;N;/^$/d;G' file.txt
每三行前面增加一个空行
sed 'N;N;/^$/d;{x;p;x;}' tmp
14、以x为开头或以x为结尾的行前后添加空行
以xi为开头的行后面添加空行
sed '/^xi/G;' tmp
以xi为结尾的行前面添加空行
sed '/^xi/{x;p;x;}' tmp
以xi为结尾的行后面添加空行
sed '/xi$/G;' tmp
以xi为结尾的行后面添加空行
sed '/xi$/{x;p;x;}' tmp
三、文本处理三剑客之 awk
1、awk 工作原理和基本用法说明
awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK
有多种版本:
AWK:原先来源于 AT & T 实验室的的AWK
NAWK:New awk,AT & T 实验室的AWK的升级版
GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容
gawk:模式扫描和处理语言,可以实现下面功能
- 文本处理
- 输出格式化的文本报表
- 执行算数运算
- 执行字符串操作
格式:
awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…
说明:
program通常是被放在单引号中,并可以由三种部分组成
- BEGIN语句块
- 模式匹配的通用语句块
- END语句块
常见选项:
- -F “分隔符” 指明输入时用到的字段分隔符
- -v var=value 变量赋值
Program格式:
pattern{action statements;..}
pattern:决定动作语句何时触发及触发事件,比如:BEGIN,END
action statements:对数据进行处理,放在{}内指明,常见:print, printf
awk 工作过程
第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块 pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
分割符、域和记录
- 由分隔符分隔的字段(列column,域field)标记1,2...n称为域标识,0为所有域,注意:和shell中变量$符含义不同
- 文件的每一行称为记录record
- 如果省略action,则默认执行 print $0 的操作
常用的action分类
- output statements:print,printf
- Expressions:算术,比较表达式等
- Compound statements:组合语句
- Control statements:if, while等
- input statements
awk控制语句
- { statements;… } 组合语句
- if(condition) {statements;…}
- if(condition) {statements;…} else {statements;…}
- while(conditon) {statments;…}
- do {statements;…} while(condition)
- for(expr1;expr2;expr3) {statements;…}
- break
- continue
- exit
2、动作 print
格式:
print item1, item2, ...
说明:
- 逗号分隔符
- 输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式
- 如省略item,相当于print $0
范例:
# awk '{print "hello,awk"}'
# awk -F: '{print "wang"}' /etc/passwd
# awk -F: '{print}' /etc/passwd
# awk -F: '{print $0}' /etc/passwd
# awk -F: '{print $1,$3}' /etc/passwd
# awk -F: '{print $1"\t"$3}' /etc/passwd
# grep "^UUID" /etc/fstab |awk {'print $2,$3'}
/ ext4
# awk '{print $6}' access.log |sort |uniq -c|sort -nr|head
523 "171.117.45.158",
36 "106.38.223.178",
35 "47.92.36.178",
20 "164.92.189.255",
20 "159.203.44.43",
19 "159.223.236.123",
19 "139.59.138.104",
14 "47.97.211.99",
14 "47.92.29.136",
13 "125.124.222.109",
# df | awk -F"[[:space:]]+|%" '{print $5}'
Use
0
0
1
0
5
1
92
1
# df | grep "^/dev/sd" | awk -F"[[:space:]]+|%" '{print $5}'
5
1
92
# df | awk -F"[[:space:]]+|%" '/^\/dev\/sd/{print $5}'
5
1
92
3、awk变量
awk中的变量分为:内置和自定义变量
常见的内置变量
FS:输入字段分隔符,默认为空白字符,功能相当于 -F
范例:
awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
awk -v FS=":" '{print $1FS$3}' /etc/passwd
awk –F: '{print $1,$3,$7}' /etc/passwd
S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd
OFS:输出字段分隔符,默认为空白字符
范例:
awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
RS:输入记录分隔符,指定输入时的换行符
范例:
awk -v RS=' ' ‘{print }’ /etc/passwd
ORS:输出记录分隔符,输出时用指定符号代替换行符
范例:
awk -v RS=' ' -v ORS='###' '{print $0}' /etc/passwd
NF:字段数量
范例:
#引用变量时,变量前不需加$
# awk -F:'{print NF}' /etc/fstab
# awk -F:'{print $(NF-1)}' /etc/passwd
# ls /misc/cd/BaseOS/Packages/*.rpm |awk -F"." '{print $(NF-
1)}'|sort |uniq -c
389 i686
208 noarch
1060 x86_64
# ss -nt |grep "^ESTAB" | awk -F"[[:space:]]+|:" '{print $(NF-2)}'
10.0.0.1
10.0.0.7
10.0.0.1
# ss -nt |awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'
范例: 将连接数超过100个以上的IP放入黑名单拒绝访问
cat deny_dos.sh
LINK=100
while true;do
ss -nt | awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'|sort |uniq -
c|while read count ip;do
if [ $count -gt $LINK ];then
iptables -A INPUT -s $ip -j REJECT
fi
done
done
NR:记录编号
范例:
# awk -F: '{print NR}' /etc/passwd
1
2
3
.......
# awk -F: 'END{print NR}' /etc/passwd
57
# awk -F: 'BEGIN{print NR}' /etc/passwd
0
FNR:各文件分别计数,记录号
范例:
awk '{print FNR}' /etc/fstab /etc/inittab
# awk '{print NR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
4 CentOS Linux release 8.0.1905 (Core)
# awk '{print FNR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
1 CentOS Linux release 8.0.1905 (Core)
FILENAME:当前文件名
范例:
# awk '{print FILENAME}' /etc/fstab
# awk '{print FNR,FILENAME,$0}' /etc/issue /etc/redhat-release
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
1 /etc/redhat-release CentOS Linux release 8.0.1905 (Core)
ARGC:命令行参数的个数
范例:
# awk '{print ARGC}' /etc/issue /etc/redhat-release
3
3
3
3
# awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release
3
ARGV:数组,保存的是命令行所给定的各参数
范例:
# awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release
awk
# awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release
/etc/issue
# awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release
/etc/redhat-release
# awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release
自定义变量(区分字符大小写)
- -v var=value
- 在program中直接定义
范例:
awk -v test='hello gawk' '{print test}' /etc/fstab
awk -v test='hello gawk' 'BEGIN{print test}'
awk 'BEGIN{test="hello,gawk";print test}'
awk -F: '{sex=“male”;print $1,sex,age;age=18}' /etc/passwd
cat awkscript
{print script,$1,$2}
awk -F: -f awkscript script="awk" /etc/passwd
4、动作 printf
printf 可以实现格式化输出
格式:
printf “FORMAT”, item1, item2, ...
说明:
- 必须指定FORMAT
- 不会自动换行,需要显式给出换行控制符,\n
- FORMAT中需要分别为后面每个item指定格式符
格式符:与item一一对应
- %c:显示字符的ASCII码
- %d, %i:显示十进制整数
- %e, %E:显示科学计数法数值
- %f:显示为浮点数
- %g, %G:以科学计数法或浮点形式显示数值
- %s:显示字符串
- %u:无符号整数
- %%:显示%自身
修饰符
#[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,如:%3.1f
- 左对齐(默认右对齐) 如:%-15s
+ 显示数值的正负符号 如:%+d
范例:
awk -F: '{printf "%s",$1}' /etc/passwd
awk -F: '{printf "%s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
awk -F: '{printf “Username: %sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %25sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %-25sUID:%d\n",$1,$3}' /etc/passwd
5、操作符
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^=,++, --
范例:
# awk 'BEGIN{i=0;print ++i,i}'
1 1
# awk 'BEGIN{i=0;print i++,i}'
0 1
比较操作符:
==, !=, >, >=, <, <=
模式匹配符:
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配
范例:
# awk -F: '$0 ~ /root/{print $1}' /etc/passwd
# awk -F: '$0 ~ "^root"{print $1}' /etc/passwd
# awk '$0 !~ /root/' /etc/passwd
# awk '/root/' /etc/passwd
# awk -F: '$3==0' /etc/passwd
# df | awk -F"[[:space:]]+|%" '$0 ~ /^\/dev\/sd/{print $5}'
5
1
92
# ifconfig eth0 | awk 'NR==2{print $2}'
10.0.0.8
逻辑操作符:
与&&,或||,非!
范例:
awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
awk -F: '!($3==0) {print $1}' /etc/passwd
awk -F: '!($3>=500) {print $3}' /etc/passwd
条件表达式(三目表达式)
selector?if-true-expression:if-false-expression
范例:
awk -F: '{$3>=1000?usertype="Common User":usertype="SysUser";printf "%-20s:%12s\n",$1,usertype}' /etc/passwd
6、模式PATTERN
PATTERN:根据pattern条件,过滤匹配的行,再做处理
1、如果未指定:空模式,匹配每一行
范例:
# awk -F: '{print $1,$3}' /etc/passwd
2、/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
范例:
# awk '/^UUID/{print $1}' /etc/fstab
# awk '!/^UUID/{print $1}' /etc/fstab
# df | awk '/^\/dev\/sd/'
/dev/sda2 104806400 4935924 99870476 5% /
/dev/sda3 52403200 398876 52004324 1% /data
/dev/sda1 999320 848572 81936 92% /boot
3、relational expression: 关系表达式,结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
范例:
awk -F: 'i=1;j=1{print i,j}' /etc/passwd
awk '!0' /etc/passwd ;awk '!1' /etc/passwd
awk -F: '$3>=1000{print $1,$3}' /etc/passwd
awk -F: '$3<1000{print $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
4、line ranges:行范围
/pat1/,/pat2/ 不支持直接给出数字格式
范例:
# awk '/^bin/,/^adm/' /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
# sed -n '/^bin/,/^adm/p' /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
# awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
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
# sed -n '3,6p' /etc/passwd
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
5、BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
范例
awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3} END{print "END FILE"}'
/etc/passwd
awk -F: '{print "USER USERID";print $1":"$3} END{print "END FILE"}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n--------------- "}{print $1,$3}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n------"}{print $1,$3}'END{print "========"}
/etc/passwd
seq 10 | awk 'i=0'
seq 10 | awk 'i=1'
seq 10 | awk 'i=!i'
seq 10 | awk '{i=!i;print i}'
seq 10 | awk '!(i=!i)'
seq 10 | awk -v i=1 'i=!i'
7、条件判断 if-else
语法:
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else{statement3}
使用场景:对awk取得的整行或某个字段做条件判断
范例:
awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
awk '{if(NF>5) print $0}' /etc/fstab
awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
awk -F: '{if($3>=1000) printf "Common user: %s\n",$1; else printf "root or Sysuser: %s\n",$1}' /etc/passwd
df -h|awk -F% '/^\/dev\/sd/{print $1}'| awk '$NF>=80{print $1,$5}'
df | awk -F"[[:space:]]+|%" '/^\/dev\/sd/{if($5>80)print $1,$5}'
awk 'BEGIN{ test=100;if(test>90){print "very good"}
else if(test>60){ print "good"}else{print "no pass"}}'
8、switch语句
语法:
switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
9、循环while
语法:
while (condition) {statement;…}
条件“真”,进入循环;条件“假”,退出循环
使用场景:
- 对一行内的多个字段逐一类似处理时使用
- 对数组中的各元素逐一处理时使用
示例:
# awk 'BEGIN{print length("hello")}'
5
# awk 'BEGIN{print length("马哥教育")}'
4
# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print
$i,length($i); i++}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF)
{if(length($i)>=10){print $i,length($i)}; i++}}' /etc/grub2.cfg
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
crashkernel=auto 16
net.ifnames=0 13
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
crashkernel=auto 16
net.ifnames=0 13
# awk 'BEGIN{ total=0;i=1;while(i<=100){total+=i;i++};print
total}'
5050
10、循环 do-while
语法:
do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
do-while循环
语法:do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
范例:
# awk 'BEGIN{ total=0;i=1;do{ total+=i;i++;}while(i<=100);print total}'
5050
11、循环for
语法:
for(expr1;expr2;expr3) {statement;…}
常见用法:
for(variable assignment;condition;iteration process) {for-body}
特殊用法:能够遍历数组中的元素
for(var in array) {for-body}
范例:
# awk 'BEGIN{total=0;for(i=1;i<=100;i++){total+=i};print total}'
5050
范例:
# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print
$i,length($i)}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
性能比较
time (awk 'BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}')
time (total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
time (for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
time (seq –s ”+” 10000|bc)
12、continue和break
格式:
continue [n]
break [n]
范例:
# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
2500
# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i}print sum}'
1225
13、next
next 可以提前结束对本行处理而直接进入下一行处理(awk自身循环)
范例:
# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
nobody 65534
polkitd 998
gluster 996
rtkit 172
rpc 32
chrony 994
saslauth 992
clevis 984
pegasus 66
colord 982
setroubleshoot 980
gdm 42
gnome-initial-setup 978
sshd 74
avahi 70
tcpdump 72
wang 1000
14、数组
awk的数组为关联数组
格式
array[index-expression]
范例:
weekdays["mon"]="Monday"
index-expression
- 可使用任意字符串;字符串要使用双引号括起来
- 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
- 若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
范例:
# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
范例:
awk '!line[$0]++' dupfile
awk '{!line[$0]++;print $0, line[$0]}' dupfile
范例:判断数组索引是否存在
# awk 'BEGIN{array["i"]="x"; array["j"]="y" ; print "i" in array, "y" in array }'
1 0
# awk 'BEGIN{array["i"]="x"; array["j"]="y" ;if ("i" in array ) {print "存在"}else{print "不存在"}}'
存在
# awk 'BEGIN{array["i"]="x"; array["j"]="y" ;if ("abc" in array ) {print "存在"}else{print "不存在"}}'
不存在
若要遍历数组中的每个元素,要使用for循环
for(var in array) {for-body}
注意:var会遍历array的每个索引
范例:遍历数组
# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
Tuesday
Monday
# awk 'BEGIN {
a["x"] = "welcome"
a["y"] = "to"
a["z"] = "Magedu"
for (i in a) {
print i,a[i]
}
}'
x welcome
y to
z Magedu
# awk -F: '{user[$1]=$3}END{for(i in user){print "username: "i,"uid: "user[i]}}' /etc/passwd
username: adm uid: 3
username: rpc uid: 32
username: dnsmasq uid: 985
username: radvd uid: 75
username: sync uid: 5
username: mail uid: 8
username: exim uid: 93
username: tss uid: 59
username: gluster uid: 996
username: unbound uid: 995
username: halt uid: 7
范例:
# cat ss.log | sed -nr '1!s/^([^0-9]+) .*/\1/p'|sort |uniq -c
529 ESTAB
9 LISTEN
128 SYN-RECV
95 TIME-WAIT
# ss -ant | awk 'NR!=1{state[$1]++}END{for(i in state){print i,state[i]}}'
SYN-RECV 128
LISTEN 9
ESTAB 529
TIME-WAIT 95
# netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}'
LISTEN 9
SYN_RECV 126
ESTABLISHED 523
FIN_WAIT2 40
# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log
172.20.0.200 1482
172.20.21.121 2
172.20.30.91 29
172.16.102.29 864
172.20.0.76 1565
172.20.9.9 15
172.20.1.125 463
172.20.61.11 2
172.20.73.73 198
# awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' access_log |sort -nr| head -3
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log |sort -k2 -nr|head -3
172.20.116.228 4870
172.20.116.208 3429
172.20.0.222 2834
范例:多维数组
# awk 'BEGIN{
> array[1][1]=11
> array[1][2]=12
> array[1][3]=13
> array[2][1]=21
> array[2][2]=22
> array[2][3]=23
> for (i in array)
> for (j in array[i])
> print array[i][j]
> }'
11
12
13
21
22
23
15、awk脚本
将awk程序写成脚本,直接调用或执行
范例:
# cat passwd.awk
{if($3>=1000)print $1,$3}
# awk -F: -f passwd.awk /etc/passwd
nobody 65534
wang 1000
mage 1001
范例:
# cat test.awk
#!/bin/awk -f
#this is a awk script
{if($3>=1000)print $1,$3}
# chmod +x test.awk
# ./test.awk -F: /etc/passwd
nobody 65534
wang 1000
mage 1001
向awk脚本传递参数
格式:
awkfile var=value var2=value2... Inputfile
注意:在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行
BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-v参数
范例:
# cat test2.awk
#!/bin/awk -f
{if($3 >=min && $3<=max)print $1,$3}
# chmod +x test2.awk
# ./test2.awk -F: min=100 max=200 /etc/passwd
systemd-resolve 193
rtkit 172
pulse 171
qemu 107
usbmuxd 113
abrt 173
获取匹配关键字后的内容
awk '{ if(match($0,"关键字")) {print substr($0,RSTART+RLENGTH) }}'文件
#示例
# 原始文本
2018-07-31T09:33:08.160102Z 1 [Note] A temporary password isgenerated for root@localhost: oco4Pr&a!o;v
# 命令
awk '{ if(match($0,"root@localhost: ")) {print substr($0,RSTAR+RLENGTH) }}' test.log
# 结果
oco4Pr&a!o;v
去除文本中的空行
awk NF test.txt
# NF代表当前行的字段数,空行的话字段数为0,被awk解释为假,因此不进行输出。
获取匹配关键字后多少的位字符串
# 样本
a="Location: https://allinone.okd311.curiouser.com:8443/oauth/token/implicit#access_token=FBHwgR1jj2coLoYYfG9SdGUke9L9HmAU2IOI9GaMKrQ&expires_in=86400&scope=user%3Afull&token_type=Bearer"
# 获取"access_token="的值
# 方式一
echo $a | grep "access_token=" |awk -F"access_token=" '/access_token=/{printf substr($2,0,43)}'
# 结果: FBHwgR1jj2coLoYYfG9SdGUke9L9HmAU2IOI9GaMKrQ
# 方式二
echo $a | grep "access_token=" |awk '{ if(match($0,"access_token=")) {print substr($0,RSTART+RLENGTH) }}'| awk -F '&' '{print $1}'
# 结果: FBHwgR1jj2coLoYYfG9SdGUke9L9HmAU2IOI9GaMKrQ
使用多个分隔符分割字符串
# @, 空格和Tab都是字段分隔符
awk -F”[@ /t]" '{print $1 $2}'
为每行增加行号
awk '$0=NR":"$0' 文件名 > 新文件名
# $0表示原来每行的内容,
# NR表示行号,
# 双引号之间表示行号与原来内容之间的delimiter
评论区