## 1. awk简介
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。
## 2. awk命令格式和选项
### 2.1 awk的语法有两种形式
~~~
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
~~~
PATTERN:匹配模式
action:print, printf(可以自定义打印格式)
![](http://om4h63cja.bkt.clouddn.com/17-6-9/70670483.jpg)
### 2.2 命令选项
~~~
-F fs or --field-separator fs
指定输入文件的分隔符,fs是一个字符串或者是一个正则表达式,如-F:、-F ab。
-v var=value or --asign var=value
赋值一个用户定义变量。
-f scripfile or --file scriptfile
从脚本文件中读取awk命令。
-W help or --help, -W usage or --usage
打印全部awk选项和每个选项的简短说明。
-W re-interval or --re-inerval
允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
-W source program-text or --source program-text
使用program-text作为源代码,可与-f命令混用。
-W version or --version
打印bug报告信息的版本。
~~~
## 3. 模式和操作
### 3.1 awk脚本是由模式和操作组成的
~~~
pattern {action} 如$ awk '/root/' test,或$ awk '$3 < 100' test
~~~
两者是可选的,如果没有模式,则action应用到全部记录,如果没有action,则输出匹配全部记录。默认情况下,每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符进行分隔。
模式
~~~
/正则表达式/:使用通配符的扩展集。
关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。
模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
END:让用户在最后一条输入记录被读取之后发生的动作。
~~~
### 3.2 操作
操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内。主要有四部份:
变量或数组赋值
输出命令
内置函数
控制流命令
## 4 awk变量
### 4.1 awk内置变量之记录变量
~~~
FS: field separator,读取文件本时,所使用字段分隔符;(-F),默认为空格
RS: Record separator,输入文本信息所使用的换行符;
OFS: Output Filed Separator,输出文本时,所使用字段分隔符;默认为空格
ORS:Output Row Separator,输出文本时,所使用行分隔符;
~~~
### 4.2 awk内置变量之数据变量
~~~
NR: The number of input records,awk命令已经处理的记录数;如果有多个文件,这个数目会把处理的多个文件中行统一计数;相当于生成序号
FNR: 与NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数;
NF:Number of Field,当前记录的field个数;
~~~
~~~
awk '{print NF}' test.txt ;统计当前行的字段数
awk '{print $NF}' test.txt ;显示当前行最后一个字段
~~~
~~~
ARGV: 数组,保存命令行本身这个字符串,如awk '{print $0}' a.txt b.txt这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt;
ARGC: awk命令的参数的个数;
FILENAME: awk命令所处理的文件的名称;
ENVIRON:当前shell环境变量及其值的关联数组;
~~~
### 4.3 用户自定义变量
gawk允许用户自定义自己的变量以便在程序代码中使用,变量名命名规则与大多数编程语言相同,只能使用字母、数字和下划线,且不能以数字开头。gawk变量名称区分字符大小写。
* 在脚本中赋值变量
在gawk中给变量赋值使用赋值语句进行,例如:
~~~
awk 'BEGIN{var="variable testing";print var}'
~~~
* 在命令行中使用赋值变量
gawk命令也可以在“脚本”外为变量赋值,并在脚本中进行引用。例如,上述的例子还可以改写为:
~~~
awk -v var="variable testing" 'BEGIN{print var}'
~~~
## 5 awk的操作符
![](http://om4h63cja.bkt.clouddn.com/17-6-9/7984318.jpg)
## 6 匹配操作符(~)
用来在记录或者域内匹配正则表达式。如$ awk '$1 ~/^root/' test将显示test文件第一列中以root开头的行。
## 7 比较表达式
`conditional expression1 ? expression2: expression3`,例如:`$ awk '{max = {$1 > $3} ? $1: $3: print max}' test`。如果第一个域大于第三个域,$1就赋值给max,否则$3就赋值给max。
~~~
$ awk '$1 + $2 < 100' test。如果第一和第二个域相加大于100,则打印这些行。
$ awk '$1 > 5 && $2 < 10' test,如果第一个域大于5,并且第二个域小于10,则打印这些行。
~~~
## 8 print
print的使用格式
print item1, item2, ...
>[info] 各项目之间使用逗号隔开,而输出时则以空白字符分隔;
输出的item可以为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出;
print命令后面的item可以省略,此时其功能相当于print $0, 因此,如果想输出空白行,则需要使用print "";
~~~
awk 'BEGIN { print "line one\nline two\nline three" }'
awk -F: '{ print $1, $3 }' /etc/passwd
awk 'BEGIN {FS=":";OFS="@"} { print $1, $3 }' /etc/passwd
~~~
## 9 printf
printf命令的使用格式
printf format, item1, item2, ...
要点:
>[info]其与print命令的最大不同是,printf需要指定format;
format用于指定后面的每个item的输出格式;
printf语句不会自动打印换行符;\n
### 9.1 format
格式的指示符都以%开头,后跟一个字符;如下:
~~~
%c: 显示字符的ASCII码;
%d, %i:十进制整数;int
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;string
%u: 无符号整数;
%%: 显示%自身;
~~~
### 9.2 修饰符
~~~
N: 显示宽度;
-: 左对齐;
+:显示数值符号;
~~~
### 例子
~~~
awk -F: '{printf "%-15s %d\n",$1,$3}' /etc/passwd
awk -F: 'BEGIN{printf "%-15s%-10s\n","USER","ID"}{printf "%-15s%-10i\n",$1,$3}' /etc/passwd
awk -F: 'BEGIN { printf "%-15s %-15s\n","user","uid";print "----------------------"} { printf "%-15s %-15d\n",$1,$3} END { print "----------------------" }' /etc/passwd
~~~
## 10 awk编程
### if-else
~~~
if (condition) {then-body} else {[ else-body ]}
~~~
~~~
awk -F: '{if ($1=="root") printf "%-15s: %s\n", $1,"Admin"; else printf "%-15s: %s\n", $1, "Common User"}' /etc/passwd
awk -F: '{if ($1=="root") {printf "%-15s: %s\n", $1,"Admin"} else {printf "%-15s: %s\n", $1, "Common User"}}' /etc/passwd
awk -F: '{if($NF ~"bash") {printf "%-10s%s\n",$1,"admin"} else {printf "%-10s%s",$1,"commo\n"}}' /etc/passwd
awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd
~~~
### while
对字段进行循环时使用,比如,判断字段长度大于4的给予显示
~~~
while (condition){statement1; statment2; ...}
~~~
~~~
awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd
awk -F: '{i=1;while (i<=NF) { if (length($i)>=4) {print $i}; i++ }}' /etc/passwd
~~~
### do-while
~~~
do {statement1, statement2, ...} while (condition)
~~~
~~~
awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd
~~~
### for
~~~
for ( variable assignment; condition; iteration process) { statement1, statement2, ...}
~~~
~~~
awk -F: '{for(i=1;i<=3;i++) print $i}' /etc/passwd
awk -F: '{for(i=1;i<=NF;i++) { if (length($i)>=4) {print $i}}}' /etc/passwd
~~~
for循环还可以用来遍历数组元素
~~~
for (i in array) {statement1, statement2, ...}
~~~
### case
语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}
### break 和 continue
常用于循环或case语句中
### next
提前结束对本行文本的处理,并接着处理下一行;例如,下面的命令将显示其ID号为奇数的用户:
~~~
# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
~~~
### awk中使用数组
array[index-expression]
要遍历数组中的每一个元素,需要使用如下的特殊结构:
for (var in array) { statement1, ... }
其中,var用于引用数组下标,而不是元素值;
例子
~~~
# awk -F: '$NF~/[^[:space:]]/{shell[$NF]++}END{for(A in shell){print A,shell[A]}}' /etc/passwd
/bin/sync 1
/bin/bash 2
/sbin/nologin 33
/sbin/halt 1
/sbin/shutdown 1
~~~
~~~
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引;
awk '{counts[$1]++} END {for(ip in counts) print counts[ip], ip}' /var/log/httpd/access_log
用法与上一个例子相同,用于统计某日志文件中IP地的访问量
~~~
### awk的内置函数
split(string, array [, fieldsep [, seps ] ])
功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从0开始的序列;
~~~
netstat -ant | awk '/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50
~~~
length([string])
功能:返回string字符串中字符的个数;
substr(string, start [, length])
功能:取string字符串中的子串,从start开始,取length个;start从1开始计数;
system(command)
功能:执行系统command并将结果返回至awk命令
systime()
功能:取系统当前时间
tolower(s)
功能:将s中的所有字母转为小写
toupper(s)
功能:将s中的所有字母转为大写
## 常用例子
### 一、文本间隔
1、在每一行后面增加一空行
~~~
sed G guo.sh
awk '{printf("%s\n\n",$0 ) }'
awk '{print $0, "\n"}'
~~~
2、将文件中原来的空行删掉,并在在每一行后边增加一空行
~~~
sed '/^$/d;G '
awk '!/^$/ {printf("%s\n\n",$0 ) }'
~~~
3、在匹配式样的行前插入一空行
~~~
sed '/good/i\\'
sed '/hello/{x;p;x;}'
awk '{ if(/hello/) printf("\n\%s\n",$0);else print $0}'
~~~
4、在匹配式样的行后插入一空行
~~~
sed '/good/a\\'
sed '/hello/G'
awk '{if(/hello/) printf("%s\n\n",$0) ;else print $0}'
~~~
5、在匹配式样的行前、行后各插入一空行
~~~
sed '/hello/{x;p;x;G;}'
awk '{ if(/hello/) printf("\n\%s\n\n",$0);else print $0}'
~~~
### 二、文本的替换
1、在每一行查找到good,然后把good替换为bad
~~~
sed 's/good/bad/'只把每行的第一个good替换为bad
sed 's/good/bad/2'只把每行的第二个good替换为bad
sed 's/good/bad/g'把每一行的所有good替换为bad
sed 's/.∗good/\1bad/'只把每一行的的最后一个good替换位bad
sed 's/.∗good.∗good/\1bad\2/'只把每一行的的倒数第二个good替换位bad
~~~
~~~
awk '{sub(/good/,"bad"); print $0}'只把每行的第一个good替换为bad
awk '{gsub(/good/,"bad"); print $0}'把每一行的所有good替换为bad
sed 's/root/good/p' test
awk '{gsub(/root/,"good");print $0}' test
awk '{gsub(/root/,"god");print $0}' test
~~~
2、只在出现字符串fell字符串的前提下,将找到的行中的good替换为bad
~~~
sed '/fell/ s/good/bad/g'
awk '{if(/fell/) gsub(/good/,"bad"); print $0 }'
~~~
3、只在不出现字符串fell字符串的前提下,将找到的行中的good替换为bad
~~~
sed '/fell/ !s/good/bad/g'
awk '{if(!/fell/) gsub(/good/,"bad"); print $0 }'
~~~
4、多单词替换,替换为一个单词
~~~
sed 's/good/bad/g;s/fell/bad/g;s/sun/bad/g'
sed 's/good\|fell\|sun/bad/g'
awk '{gsub(/good|fell|sun/,"bad") ; print $0}'
~~~
5、倒置所有行,第一行变为最后一行(模拟tac)
~~~
sed '1!G;h;$!d'
sed -n '1!G;h;$p'
awk '{A[i++]=$0} END{for (j=i-1;j>=0;j--) print A[j]}'
~~~
6、将每两行连接为一行
~~~
sed '$!N;s/\n/ /'
awk '{f=!f;if(!f) printf("%s",$0);else printf("%s\n",$0)}'
~~~
7、在文件中每隔5行显示一空行
~~~
sed '0~5G'
sed 'n;n;n;n;G'
awk '{print $0 ;i++;if(i==5) {printf( "\n") ;i=0}}'
~~~
#### 三、选择性的显示特定行
1、显示文件的前10行
~~~
sed 10q
awk '{print ;if(NR==10) exit }'
~~~
2、显示文件的第一行
~~~
sed q
awk '{ print;exit}'
~~~
如何用sed打印文件范围从第二行至倒数第二行?
sed '1d;$d'
1、求和
~~~
cat data|awk '{sum+=$1} END {print "Sum = ", sum}'
~~~
2、求平均
~~~
cat data|awk '{sum+=$1} END {print "Average = ", sum/NR}'
~~~
3、求最大值
~~~
cat data|awk 'BEGIN {max = 0} {if ($1+0 > max+0) max=$1 fi} END {print "Max=", max}'
~~~
4、求最小值(min的初始值设置一个超大数即可)
~~~
awk 'BEGIN {min = 1999999} {if ($1<min) min=$1 fi} END {print "Min=", min}'
~~~
5、求访问次数的Top 10 Resource,可以根据此进行优化
~~~
cat output/logs/cookie_logs/`date +%u`/cookie_log|grep -v '172.16'|grep -v '127.0.0.1' |awk -F' ' '{ if(index($1,"219.141.246")!=0) print $2; else print $1 } '|sort|uniq -c|sort -n |tail -n 10
~~~
连接状态
~~~
netstat -lnta | awk '{stat[$6]++} END {for (i in stat){print i,stat[i]}}'
~~~
查看日志
~~~
awk '{a[$1]+=1} END {for(i in a){print a[i], i}}' log | sort -rn
~~~
- 目录
- 离散的内容
- IO模型
- 网卡绑定
- ssh
- 硬件测试
- 硬件
- limits
- 网络流量
- 硬盘IO
- 硬盘
- tmux
- 主机名和域名
- http_proxy
- iptables
- 内核参数
- 块设备和字符设备
- 内存
- 虚拟内存并非交换分区
- 网络延时
- 概念
- 多核压缩
- linux基础
- SSH协议
- 软件管理
- yum
- 制作本地源 yum系列
- 制作本地源 apt系列
- apt
- 在 Linux 中移除从源代码安装的程序的一种简单的方法
- 其他
- 源码编译和二进制安装后更改配置
- DNS
- bind
- 守护进程
- 特殊权限
- limit.conf配置
- 网络
- shell-ok
- 变量ok
- 数组ok
- 系统变量和环境变量
- 运算符和计算-ok
- 条件测试-ok
- 选择-ok
- shell循环-ok
- 输出echo和printf-ok
- 技巧-ok
- pre-web
- http协议
- web服务器
- Apache
- apache安装
- yum安装
- 二进制安装
- 编译安装
- httpd命令
- 运行 监控apache
- apache配置文件
- 常用配置
- MPM多处理模块
- 编译模块
- apache模块
- apache核心模块
- apache标准模块
- apache第三方模块
- 虚拟主机
- 1
- CGI-FastCGI-SSI
- 别名和重定向
- apache应用
- 301重定向
- apache防盗链
- http转化为https
- 访问时间段控制
- 控制访问目录
- 限制指定USER_AGENT
- 不同客户端访问不同网页
- apache黑名单
- httpd之禁止解析php
- 不记录css/js/img的访问日志
- 浏览器端静态缓存
- apache访问日志自动切割
- order-require
- 压缩传输
- httpd-ssl
- apache代理
- 正向代理
- 反向代理
- apache调优
- httpd压力测试工具ab
- CGI测试
- php
- php原理
- httpd和php的结合方式
- php yum安装之DSO模式
- php 编译安装之DSO模式
- php-fpm详解
- php yum安装之php-fpm模式
- php 编译安装之FastCGI模式
- php扩展之mysql
- php扩展之gd
- php扩展之pcntl
- php扩展之xcache
- php扩展之ZendGuardLoader
- phpMyAdmin
- wordpress
- 数据库-mysql
- 数据库原理
- mysql数据库原理
- mysql源码编译安装
- mysql二进制包安装
- mysql命令行工具
- 更改密码
- 数据库授权grant
- mysql日志
- 命令
- 常用
- 小命令大作为
- awk 报告生成器
- 网络命令
- 命令查找
- 压缩归档命令
- 文件管理
- 文件管理命令
- 文件查看命令
- 目录管理命令
- 用户管理命令
- 用户权限管理
- curl
- cheat
- chrony
- command
- crontab任务计划
- cut
- date
- dd
- df
- echo
- find
- grep
- hash
- iftop
- kill pkill killall
- ls
- lsmod和modprobe
- lsof
- man
- mkpasswd
- mount
- mtr
- netstat
- nmap
- nc
- NTP
- passwd
- rm
- rdate
- pv
- sar系统活动情况报告
- sed文本处理命令
- setup
- screen
- shutdown
- sort 命令
- sudo
- tcpdump
- top
- uniq
- wget
- who
- xargs
- 监控
- zabbix邮件报警
- Redis
- redis安装
- redis数据类型和操作方法
- redis持久化和配置
- redis主从配置
- php连接redis
- redis实现session共享
- 安装测试
- redis设置密码
- ELK日志分析系统
- elasticsearch
- logstash
- logstash插件
- filebeat日志收集
- kibana
- jenkins
- jenkins安装与配置
- 案例1
- 案例2
- 案例3
- 代码仓库之svn
- svn服务端配置
- 常用操作
- svn备份
- LB集群
- LVS负载均衡集群
- ipvsadm使用方法
- LVS调度方法
- NAT原理
- NAT实践
- DR原理
- DR实践
- TUN原理
- LVS持久连接
- HA集群
- HPC集群
- 共享存储
- ftp协议
- vsftpd
- NFS
- 网站架构发展
- 文件同步
- rsync基本用法
- rsync安装和使用_拉取模式
- lsyncd安装和用法
- zabbix
- zabbix服务端安装
- zabbix客户端安装
- zabbix编译安装
- zabbix监控tomcat
- zabbix监控mysql
- gitlab
- supervisor
- nsq
- ruby
- nodejs
- consul
- mesos
- zookeeper
- rwho
- 对象存储
- 工具
- rclone
- minio
- linux 性能调优
- CPU
- 第一部分 CPU
- 安全