awk

声明一个关联数组变量:
declare -A  a
             -a  
             -i    整数变量
             -r   只读变量
             -x  全局变量
awk  'BEGIN{a["mon"]=monday;a["sun"]=sunday;print a["mon"]}'
 
 
awk 'BEGIN{b[0]="monday"; b[1]="sunday";for  (i=0;i<=1;i++) {print b[i]}}'
 
一、print
print的使用格式:
print item1, item2, ...
要点:
1、各项目之间使用逗号隔开,而输出时则以空白字符分隔;
2、输出的item可以为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出;
3、print命令后面的item可以省略,此时其功能相当于print $0, 因此,如果想输出空白行,则需要使用print "";
 
例子:
# awk 'BEGIN { print "line one line two line three" }'
awk -F: '{ print $1, $3 }' /etc/passwd
 
 
二、awk变量
 
2.1 awk内置变量之记录变量:
FS: field separator,读取文件本时,所使用字段分隔符;
RS: Record separator,输入文本信息所使用的换行符;
OFS: Output Filed Separator: 
ORS:Output Row Separator:
 
awk -F:
OFS="#"
FS=":"
 
 
2.2 awk内置变量之数据变量:
NR: The number of input records,awk命令所处理的记录数;如果有多个文件,这个数目会把处理的多个文件中行统一计数;
NF:Number of Field,当前记录的field个数;
FNR: 与NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数;
ARGV: 数组,保存命令行本身这个字符串,如awk '{print $0}' a.txt b.txt这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt;
ARGC: awk命令的参数的个数;
FILENAME: awk命令所处理的文件的名称;
ENVIRON:当前shell环境变量及其值的关联数组;
 
如:awk 'BEGIN{print ENVIRON["PATH"]}'
 
2.3 用户自定义变量
 
gawk允许用户自定义自己的变量以便在程序代码中使用,变量名命名规则与大多数编程语言相同,只能使用字母、数字和下划线,且不能以数字开头。gawk变量名称区分字符大小写。
 
2.3.1 在脚本中赋值变量
 
在gawk中给变量赋值使用赋值语句进行,例如:
awk 'BEGIN{var="variable testing";print var}'
awk  'BEGIN{a="country";print a}'
centos6.4经验证,脚本中变量值为字符串类型时,必须加双引号""才能正常打印。
 
2.3.2 在命令行中使用赋值变量
 
gawk命令也可以在“脚本”外为变量赋值,并在脚本中进行引用。例如,上述的例子还可以改写为:
#awk -v var="variable testing" 'BEGIN{print var}'
#awk  'BEGIN{a=2} {print a}'  file
#awk  'a=2  {print a}'  file
#free | sed -n '2p'| awk   'x=int(($3/$2)*100) {print x}' | sed  's/$/%/'
 
三、printf
printf命令的使用格式:
printf format, item1, item2, ...
# printf  "%-12s  %6i " qwert 110
要点:
1、其与print命令的最大不同是,printf需要指定format;
2、format用于指定后面的每个item的输出格式;
3、printf语句不会自动打印换行符;
 
format格式的指示符都以%开头,后跟一个字符;如下:
%c: 显示字符的ASCII码;
%d, %i:十进制整数;
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身;
 
修饰符:
N: 显示宽度;
-: 左对齐;
+:显示数值符号;
 
例子:
# awk  -F:  '{printf "%-15s %i ",$1,$3}' /etc/passwd
# printf  "%-20s       %.4f " dingzhao 110.1100980
四、输出重定向
 
print items > output-file
print items >> output-file
print items | command
 
特殊文件描述符:
/dev/stdin:标准输入
/dev/sdtout: 标准输出
/dev/stderr: 错误输出
/dev/fd/N: 某特定文件描述符,如/dev/stdin就相当于/dev/fd/0;
 
例子:
# awk -F: '{printf "%-15s %i ",$1,$3 > "/dev/stderr" }' /etc/passwd
 
 
六、awk的操作符:
 
6.1 算术操作符:
 
-x: 负值
+x: 转换为数值;
x^y: 
x**y: 次方
x*y: 乘法
x/y:除法
x+y:
x-y:
x%y:
 
6.2 字符串操作符:
只有一个,而且不用写出来,用于实现字符串连接;
 
6.3 赋值操作符:
=
+=
-=
*=
/=
%=
^=
**=
 
++
--
 
需要注意的是,如果某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替代;
 
6.4 布尔值
 
awk中,任何非0值或非空字符串都为真,反之就为假;
 
6.5 比较(关系)操作符:
x < y True if x is less than y. 
x <= y True if x is less than or equal to y. 
x > y True if x is greater than y. 
x >= y True if x is greater than or equal to y. 
x == y True if x is equal to y. 
x != y True if x is not equal to y. 
x ~ y True if the string x matches the regexp denoted by y. 
x !~ y True if the string x does not match the regexp denoted by y. 
subscript in array   True if the array array has an element with the subscript subscript.
 
6.7 表达式间的逻辑关系符:
&&
||
!
6.8 条件表达式:
selector?if-true-exp:if-false-exp
 
if selector; then
  if-true-exp
else
  if-false-exp
fi
 
三目运算符:
a=2
b=1
c=$(($a<$b?$a:$b))
echo $c
 
6.9 函数调用:
function_name(para1,para2)
 
 
 
 
七 awk的模式:
 
awk 'program' input-file1 input-file2 ...
其中的program为:
pattern { action }
pattern { action }
...
 
7.1 常见的模式类型:
1、Regexp: 正则表达式,格式为/regular expression/
2、expresssion: 表达式,其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 == "magedu",用运算符~(匹配)和!~(不匹配)。
3、Ranges: 指定的匹配范围,格式为pat1,pat2
4、BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次
5、Empty(空模式):匹配任意输入行;
 
7.2 常见的Action
1、Expressions:
2、Control statements
3、Compound statements
4、Input statements
5、Output statements
 
 
/正则表达式/:使用通配符的扩展集。
 
关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。
 
模式匹配表达式:
 
模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
 
BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
 
END:让用户在最后一条输入记录被读取之后发生的动作。
 
 
 
 
 
八 控制语句:
8.1 if-else
语法:if (condition) {then-body} else {[ else-body ]}
# awk  -F:  '{if ($3==0) {print $1, "Adminitrator"} else { print $1,"Common User"}}' /etc/passwd
例子:
awk -F: '{if ($1=="root") print $1, "Admin"; else print $1, "Common User"}' /etc/passwd
awk -F: '{if ($1=="root") printf "%-15s: %s ", $1,"Admin"; else printf "%-15s: %s ", $1, "Common User"}' /etc/passwd
awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd
awk -F: '{if ($3==0) {print $1,"admin";print "it is root"} else print $1,"common-user"}' /etc/passwd |less
awk -F: '{if($1=="root"){print "root"}else if($1=="bin"){print "bin"}else{print "game over"} }'  /etc/passwd
awk 'BEGIN {FS=":"} { if ($3 >= 30 && $3 <= 40) {print  $0}}' /etc/passwd
 
 
 
 
8.2 while
语法: 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
awk '{i=1;while (i<=NF) {if ($i>=100) print $i; i++}}' hello.txt
 
hello.txt文件的内容为一堆随机数。
 
语法: do {statement1, statement2, ...} while (condition)
8.3 do-while 至少执行一次循环体,不管条件满足与否
awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd
awk -F: '{i=4;do {print $i;i--}while(i>4)}' /etc/passwd
 
8.4 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; ...}
awk -F:  '$NF!~/^$/{BASH[$NF]++}  END{for(A in BASH)  {printf "%15s:%i ",A,BASH[A]}}'    /etc/passwd
 
BASH[/bin/bash]++
 
BASH[/sbin/nologin]
 
BASH[/bin/bash]=1
BASH[/sbin/nologin]=2
BASH[/bin/sync]=1
 
/bin/bash: 1
/sbin/nologin: 2
/bin/sync: 1
 
8.5 case
语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}
switch语句在CentOS7系列中使用正常,在6中使用会报错误提示
 
8.6 break 和 continue
常用于循环或case语句中
 
8.7 next
提前结束对本行文本的处理,并接着处理下一行;例如,下面的命令将显示其ID号为奇数的用户:
# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
 
 
九 awk中使用数组
 
9.1 数组
声明一个关联数组:declare -A arr
array[index-expression]
 
index-expression可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用index in array
 
的方式。
 
要遍历数组中的每一个元素,需要使用如下的特殊结构:
for (var in array) { statement1, ... }
其中,var用于引用数组下标,而不是元素值
 
例子:
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(url in counts) print counts[url], url}'   /var/log/httpd/access_log
用法与上一个例子相同,用于统计某日志文件中IP地的访问量
 
获取数组的长度:${#arr[*]}或者${#arr[@]}
获取数组的下标(key):${!arr[*]}或者${!arr[@]}
 
 
 
 
 
 
9.2 删除数组变量
 
从关系数组中删除数组索引需要使用delete命令。使用格式为:
 
delete  array[index]
 
 
 
十、awk的内置函数
 
split(string, array [, fieldsep [, seps ] ])转换为数组
功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从1开始的序列;
root:x:0:0:root:/root:/bin/bash
 
user[1]=root
user[2]=x
...
user[7]=/bin/bash
 
 
 
# netstat -ant | awk '/:80>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50
 
# netstat -tan | awk '/:80>/{split($5,clients,":");ip[clients[4]]++}END{for(a in ip) print ip[a],a}' | sort -rn | head -50
 
# df -lh | awk '!/^File/{split($5,percent,"%");if(percent[1]>=20){print $1}}'
 
length([string])
功能:返回string中变量,字符串中字符的个数;
awk -v hello=aaaaaaa 'BEGIN{print length(hello)}'//返回7
awk 'BEGIN{print length("abcdef")}'//返回6,字符串得加双引号。
awk 'BEGIN{print length(1234)}'//返回4
 
substr(string, start [, length])字符串截取
功能:取string字符串中的子串,从start开始,取length个;start从1开始计数;
 awk  'BEGIN{a="country";print substr(a,5,3)}'
awk脚本中涉及到下标的都是从1开始排序,而不是从0.
 
sub(),gsub()字符串替换
[root@localhost ~]# netstat -antp |awk 'BEGIN{a="herhim";sub(/h/,"A",a);print a}'
Aerhim
[root@localhost ~]# netstat -antp |awk 'BEGIN{a="herhim";gsub(/h/,"A",a);print a}'
AerAim
 
[root@agent1 ~]# cat data1
1 3 3
2 4 6 
3 6 8 
[root@agent1 ~]# awk '{sub(/w/,"00&");print $0}' data1     <sub()函数里以正则表达式匹配时,必须放在/../里>
001 3 3
002 4 6 
003 6 8 
[root@agent1 ~]# awk '{sub($2,"00&");print $0}'  data1
1 003 3
2 004 6 
3 006 8 
[root@agent1 ~]# awk '{sub(4,"00&");print $0}'  data1
1 3 3
2 004 6 
3 6 8 
 
 
 
 
三元表达式awk 'BEGIN{c=2<1?0:100;print c}'
 
 
 
system("command")
功能:执行系统command并将结果返回至awk命令
 
systime()
功能:取系统当前时间戳
#awk  'BEGIN{date=systime();day=strftime("%F %T",date);print day}'
#awk  'BEGIN{print strftime("%F %T",1464847888)}'把某个时间戳格式化输出。
#awk  'BEGIN{print strftime("%F %T")}'格式化输出当前时间。
 
tolower(s)
功能:将s中的所有字母转为小写
[root@localhost ~]# awk  'BEGIN{a="country";print tolower(a)}'
country
[root@localhost ~]# awk  'BEGIN{a="country";print toupper(a)}'
COUNTRY
toupper(s)
功能:将s中的所有字母转为大写
 
十一、用户自定义函数
自定义函数使用function关键字。格式如下:
function F_NAME([variable])
{
statements
}
函数还可以使用return语句返回值,格式为“return value”。
#awk  'function F1() {print "hello,world"}  BEGIN{F1()}'
 
函数库:
file1文件里定义了若干个函数:
function info() {
  name="dingzhao"
  age=28
  print name
  print age
}
 
function date() {
   time=systime()
   day=strftime("%F %T",time)
   print day
}
 
脚本文件file2:
BEGIN{info();date();print "over"}
 
#awk -f file1 -f file2,输出如下:
dingzhao
28
2016-03-30 16:29:11
over
注意:-f 参数不能与awk内联脚本放到一起使用,可使用多个-f命令行参数解决。以下形式无效:
#awk -f 1.sh 'BEGIN{info();date();print "over"}'
 
awk脚本文件传递参数:
#awk  -f 3.txt  arg1=value1 arg2=value2  /etc/passwd
在sh脚本文件中给awk程序传递变量参数:
#awk  -f 3.txt  arg1=$1  arg2=$2  /etc/passwd
 
还可以通过内置数组ARGV读取命令行参数:
#awk -f 1.awk  dingzhao 31
#cat 1.awk

function a(){
print ARGV[1]
print ARGV[2]
}

BEGIN{a()}

 
(公开课笔记):
只显示第一行:awk  -F':'    'NR==1 {print $0}'   /etc/passwd
只显示最后一行:awk -F':'  'END{print $0}'  /etc/passwd
只显示最后一列:awk -F':'  '{print $NF}'  /etc/passwd
不显示第一行: awk  -F':'    'NR!=1'  /etc/passwd
不显示最后一列:awk -F':'   -v OFS=':'  '{NF--;print $0}'    /etc/passwd
 
 
练习:1、统计当前系统上每个客户端IP的连接中处于TIME_WAIT的连接状态的个数;
           2、统计ps aux命令执行时,当前系统上各状态的进程的个数;
           3、统计ps aux命令执行时,当前系统上各用户的进程的个数;
    4、显示ps aux命令执行时,当前系统上其VSZ(虚拟内存集)大于10000的进程及其PID;
          5,统计每行的总数;
 [root@agent1 ~]# cat data1
1 3 5 
2 4 6 
3 6 8 
#awk '{for(i=1;i<=NF;i++){sum[NR]+=$i}} END{for(a in sum){print a,sum[a]}}' data1 或
#awk '{print NR": "$1+$2+$3}' data1 或
#awk '{sum=0;for(i=1;i<=NF;i++){sum+=$i};print NR":"sum}' data1
 
 
 
 
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/as007012/p/10009093.html