文本三工具grep sed awk
grep egrep fgrep 文本过滤
sed 行编辑器
模式空间、保持空间
awk 报告生成器,格式化文本输出
AKW: Aho,Weinberger,Kernighan 这个工具的三个人的作者
1970s出现的-->New AWK ,NAWK
linux上用的是GNU awk 简称为gawk
gwak -pattern scanning and processing language
处理:一次读取一行文本,根据指明的输入分隔符切割为n个组成部分;内
建变量$1...$n 显示整行片段为$0
基本用法:gawk [options] 'program' FILE1 [FILE...n]
program: PATTREN{ACTION STATEMENTs}
语句之间用;分隔
选项
-F ""指明字段分隔符
-v var=value :自定义变量
1、print
print item1,item2,...
例如 awk '{print $1,$2}' 以默认空格为分割字段显示$1 $2
不写,的话会连接显示 $1$2
(1)都号分隔符
(2)输出的item可以是字符串,数值,当前记录的子段、变量或awk表达式
字符串连接时 '{print "hello:" $1}' 加入字符 ""里面的东西不会改变,
因此$1不能在""里面
(3)省略item,就相当于print $0 打印整行
2、变量
1 内建变量
FS:input filed seperator,默认为空白字符
OFS:output filed seperator,默认为空白字符
RS: 输入时的换行符
ORS:输出时的换行符
NF:显示行的字段数
这个时候如果打印$NF 是打印每行字段的最后一个字段
因为你统计了每行的字段
{print NF} {print NR}
因此打印变量不要加$
NR:统计文件的行数
FNR:每个文件单独计数行数 {print FNR} file1 file2 ..
FILENAME:当前正在处理的文件名
如果直接打印,是每处理一行就会显示一次文件名
可以用 'BEGIN{print FILENAME}' 显示一次
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行中所给定的各参数
例如 awk 'BEGIN{print ARGV[0] ARGV[1] ARGV[2] ARGC}' file1 file2
就会显示 awk file1 file2 3 三个参数和总计的参数量
例如
eg1: awk -v FS=':' '{print $1}' /etc/passwd
等于awk -F: '{print $1}' /etc/passwd
eg2:定义输出分隔符
awk -v FS=':' -v OFS=':' '{print $1}' /etc/passwd
输出也打印为分割符为:
eg3 -v RS=' ' 把空白字符全部当做换行符
-v ORS='#' #作为输出的换行
2 自定义变量
-v var=value
变量名区分大小写、引用变量不需要$
如果不对文件做处理,必须'BEGIN{}' 而不是在处理文件过程中,就不用加文件名称了
3printf 命令
格式化输出:printf FORMAT, item1 ....
(1)FORMAT必须给出
(2)printf不会自动换行,需要显式给出\n
(3)FORMAT中需要分别为后面的每个item指定一个格式化符号
格式符
%c 显式字符的ASCII码
%d,%i 显式为十进制,整数
%e,%E 显式为科学计数法
%f 显式为浮点数
%g,%G以科学计数法,浮点形式显式数值
%s显式字符串
%u 无符号整数
%% 显式% 本身
例如 awk -F: '{printf "Username: $s\n",$1}' /etc/passwd
类似C语言版的输出
awk -F: '{printf "Username: $s, UID:%d\n",$1,$3}' /etc/passwd
修饰符
#[.#]: 第一个#控制显示的宽度,第二个#控制小数的精度可以不加
%3.1f
awk -F: '{printf "Username: $15s, UID:%8d\n",$1,$3}' /etc/passwd
默认为右对齐显示
-为左对齐
awk -F: '{printf "Username: $-15s, UID:%8d\n",$1,$3}' /etc/passwd
%-15s 左对齐
-左对齐
+显示数值的符号
4操作符
算数操作符:
x-+\*^%
-x 负值
+x 转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符
=,+=,-=,*=,%=,^=,\=
++,--
比较操作符
< > >= <= == !=
模式匹配符
~ 是否匹配
!~是否不匹配
逻辑操作符
&& ||
!
函数调用
function_name(argu1,argu2, ...)
条件表达式
selector?if-true-expression:if-false-expression
1?2:3
1对执行2,不对执行3
eg: awk -F: '{$3>=1000?usertype="common":usertype="sys";printf
"%15s:%-s\n",$1,usertype}' /etc/passwd
5 PATTERN
(1) empty:空模式,匹配每一行
(2)/regular expression/ :仅处理能被此处模式匹配到的行(过滤)
eg1: awk '/^UUID/{print $1}' /etc/fstab
仅显示开头为UUID 的行
awk '!/^UUID/{print $1}' /etc/fstab
加!对整个过滤模式取反
正则表达式
(3)relational expression:关系表达式:如果有“真”有“假”;结果为真才被处理
真:结果为非0值,非空字符串
eg: awk -F: '$3>=1000{prinf $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
打印最后一个字段为/bin/bash的行
(4)line ranges:行范围,
startline,endline (地址定界) /pat1/ /pat2/
注意:不支持直接给出数字的格式
awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
(5)BEGIN/END模式
BEGIN{} 在开始处理文件中的文本之前执行一次
END{}在文本处理完成之后执行一次
6常用的action
(1)表达式Expressions
(2)控制语句
(3)组合语句
(4)输入语句
(5)输出语句
7控制语句
if(confition) {statements}
if(confition) {statements} else {statements}
...
...
7.1 if-else
语法: if(conditon) statement [else statement]
awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd
awk -F: '{if($3>=1000) {print $1,$3} else {print $1,$3}}' /etc/passwd
df -h|awk -F[%] '{print $5}' |awk '{print $NF}'
显示最后一个字段
df -h|awk -F[%] '/^\/dev/{print $5}' |awk '{print $NF}'
\/转义 以/dev开头的行
7.2while循环
语法:while(conditon) statement
条件“真”,进入循环;条件“假”,退出循环
使用场景:对一行内的多个字段逐一类似处理时使用;对数组元素逐一处理
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub2.cfg
统计字段
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)};i++}}' /etc/grub2.cfg
统计字段
7.3 do-while循环
do statement while(condition)
至少执行一次循环体
7.4for循环
语法:for(expr1;expr2;expr3) statement
for(variable assignment;condition;iteration process) {for-body}
7.5 switch语句
语法:switch(expression)
switch(expression){
case VALUE1 or /REGEXP/
statement;
case 2
...
default:statement
}
7.6 break continue
break [n]
continue
7.7next
提前结束对本行的处理而直接进入下一行
awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
8array
关联数组array[index-expression]
index-expression
(1)可使用任意字符串
(2)如果某数组元素事先不存在,在引用时awk会自动创建此元素,并且初始化为
“空串”
要判断数组中是否存在某元素,要使用“index in array”格式进行
weekdays["mon"]="Monday" 引用元素不要加$
要使用双引号
eg: awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]=Tuesday;print weekdays["mon"]}'
遍历数组中每个元素
for(var in array) {for-body}
var会遍历array的每个索引
netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'
其中 state[$NF]++表示 索引数组的自增
结果为
Listen 3
Establish 3
用于统计服务很给力
awk '{ip[$1]++}END{for (i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
这就是所谓的报告生成器
例题:
1统计/etc/fstab中每个文件系统类型出现的次数
awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
2统计指定文件中每个单词出现的次数
行内字段遍历
awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for (i in count) {print i,count[i]}}' /etc/fstab
9函数
9.1内置函数
数值处理
rand() 返回0-1之间一个随机数
字符串处理
length([s]) 返回指定字符串的长度
sub(r,s,[t]) r表示模式来查找t所表示的字符串中的匹配的内容,并将其第一次出现替换为s
gsub(r,s,[t]) 全局替换
split(s,a,[r]) 以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中。数组从1标号
例如 netstat -tan |awk '/^tcp\>/{split($5,ip,":");print ip[1]}' 打印每一行的ip
netstat -tan |
awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
统计ip次数
9.2自定义函数