awk

Linux使用到的文本处理工具

三者都支持正则表达式

grep文本过滤(性能比awk好的多)

sed   尤其适用在脚本中

awk  文本格式化工具,报告生成器,本身不编辑文本,工作与遍历模式下,迭代,每次读一行。

一、命令格式

awk [ options] ‘/pattern/{action}’

options

-F

指定行分隔符

-v

用户自定义变量


/pattern/

定界

指定的匹配范围,addr1,addr2

表达式

其值非0或为非空字符时满足条件,如:$1 ~ /foo/ $1 == "magedu",用运算符~(匹配)!~(不匹配)

BEGIN{}:

在遍历操作开始之前执行一次

END{}

在遍历操作结束之后、命令退出之前执行一次

正则表达式


空模式

匹配任意输入行


action

print


printf


Expressions:

表达式

Control statements

控制语句

Compound statements

组合语句

Input  statements

输入语句

Output  statements

输出语句


二、awk编程语言

awk会对整个文件的每一行进行遍历扫描,对单一的行,我们还可以进行扫描循环

主要的要素

1.变量、数组

记录变量




$0

代表当前的行


FS

field  separator ,读取文件本时,所使用字段分隔符

eg:[root@localhost  ~]# awk 'BEGIN{FS=":"}/root/{print $1,$NF}' /etc/passwd


RS

record  separator,输入文本信息所使用的换行符;(读行的时候的行分隔符是什么)

eg:


OFS

out  filed separator 输出时以什么作为分隔符

eg:[root@localhost  ~]# awk 'BEGIN{FS=":";OFS=":"}/root/{print $1,$NF}'  /etc/passwd


ORS

output  row separator(输出的时候行分隔符是什么)

eg:[root@localhost  ~]# awk 'BEGIN{FS=":";ORS="#"}{print $0}' /etc/passwd

eg[root@localhost ~]# awk  'BEGIN{RS=":";ORS="#"}{print $0}' /etc/passwd


数据变量




NR

the  number of input recordsawk命令所处理的记录数;如果有多个文件,这个数目会把处理的多个文件中行统一计数

(同时看多个文件,大家一起计行数)

eg:

# awk '{print NR,$0}' /etc/fstab /etc/issue


NF

Number  of Field,当前记录的field个数


FNR

NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数;

(同时看多个文件,各自计行数)

eg:

#  awk '{print FNR,$0}' /etc/fstab /etc/issue


ARGV

数组,保存命令行本身这个字符串,如awk '{print $0}' a.txt b.txt这个命令中,ARGV[0]保存awkARGV[1]保存a.txt

eg:

#  awk -F: '/root/{print $1 ,"is a user in ", ARGV[1]}' /etc/passwd


ARGC

awk命令的参数的个数

eg:

#  awk 'BEGIN {print ARGC}' /etc/passwd /etc/issue


FILENAME

awk命令当前所处理的文件的名称

eg

#  awk -F: '{print $0 ,"in",FILENAME}' /etc/fstab


ENVIRON

当前shell环境变量及其值的关联数组

用户自定义变量


gawk允许用户自定义自己的变量以便在程序代码中使用,变量名命名规则与大多数编程语言相同,只能使用字母、数字和下划线,且不能以数字开头。gawk变量名称区分字符大小写。

-v

eg:

#  awk -v num1=20 -v num2=30 'BEGIN{print num1+num2}'

eg:

#  awk 'BEGIN{num1=10;num2=20;print num1+num2}'


在脚本中赋值变量

赋值变量在gawk中给变量赋值使用赋值语句进行,例如:

awk  'BEGIN{var="variable testing";print var}'


在命令行中使用赋值变量

gawk命令也可以在“脚本”外为变量赋值,并在脚本中进行引用。例如,上述的例子还可以改写为:

awk  -v var="variable testing" 'BEGIN{print var}'

注意:


$变量是显示字段的值,显示变量自身是不能加$

数组的使用


数组,数字索引关联数组,字串索引

declear –a A

A=([1]=’a’ [2]=’b’)

echo ${A[1]}

decleare –A test

test=([a]=’a’ [b]=’b’)

echo ${test[a]}

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地的访问量

下面是非常实用的两个示例

# netstat -tn | awk '/^tcp/{tcp[$6]++}END{for(i in tcp) {printf "%20s %s\n",i,tcp[i]} }'
#统计当前监听到的IP地址
# awk '! /^$/{access[$1]++}END{for(i in access) {printf "%20s %s\n",i,access[i]}}'  /var/log/httpd/access_log
#统计访问过系统的用户


删除数组变量

从关系数组中删除数组索引需要使用delete命令。使用格式为:


       delete     array[index]


2.控制语句

if-else

语法:if (condition) {then-body} else {[  else-body ]}


awk -F:   '{if ($3 == 0) {print $1, "administrator";} 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\n",  $1,"Admin"; else printf "%-15s: %s\n", $1, "Common  User"}' /etc/passwd

awk  -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd

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

do-while

至少执行一次循环体,不管条件满足与否

语法: do {statement1, statement2,  ...} while (condition)


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

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\n",A,BASH[A]}}' /etc/passwd

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

3.tor行,我们还可以进行内置函数

split

split(string,  array [, fieldsep [, seps ] ])

功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从1开始的序列;


# 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

length([string])

功能:返回string字符串中字符的个数;

substr

substr(string,  start [, length])

功能:取string字符串中的子串,从start开始,取length个;start1开始计数


system(command)

功能:执行系统command并将结果返回至awk命令

systime()

功能:取系统当前时间

tolower(s)

功能:将s中的所有字母转为小写

toupper(s)

功能:将s中的所有字母转为大写


实用示例

# df -lh | awk '!/^File/{split($5,space,"%");if(space[1]>=20){print $1}}'
# awk '/GET/{split($7,s,"?");res[s[1]]++}END{ for(i in res) {printf "%23s,%s",i,res[i]}}'
# df -lh | awk '!/^File/{split($5,space,"%");if(space[1]>=20){print $1}}'
#统计磁盘使用状况
# awk '/GET/{split($7,s,"?");res[s[1]]++}END{ for(i in res) {printf "%23s,%s",i,res[i]}}' access_log
#统计访问当前web服务器的资源


4.自定义函数

5.函数调用

function_name(para1,para2)

6.条件表达式

使用较少,这里仅给出知识点

selector?if-true-exp:if-false-exp
if selector; then
 if-true-exp
else
  if-false-exp
fi
a=3
b=4
eg:# awk -v a=2 -v b=3    'BEGIN{a>b?max=a:max=b;print max}'
a>b?a is max:b ia max


7.操作符

算术操作符

-x:  负值


+x:  转换为数值


x^y:


x**y:  次方


x*y:  乘法


x/y:除法


x/y:除法


c


x-y


x%y

字符串操作符

只有一个,而且不用写出来,用于实现字符串连接

赋值操作符

=

+=

-=

*=

/=

%=

^=

**=

++

--

需要注意的是,如果某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替代;

布尔值

awk中,任何非0值或非空字符串都为真,反之就为假

比较操作符

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.

表达式间的逻辑关系符:

&&

||




三、输出

awk默认输出为空格

数据需要流式化

print

print  item1, item2, ...


1、各项目之间使用逗号隔开,而输出时则以空白字符分隔

2、输出的item可以为字符串或数值、当前记录的字段($1)、变量或awk的表达式;数值会先转换为字符串,而后再输出

3、print命令后面的item可以省略,此时其功能相当于print $0,

4、如果想输出空白行,则需要使用print ""


eg  :awk 'BEGIN { print "line one\nline two\nline three" }'

awk  -F: '{ print $1, $3 }' /etc/passwd

printf

默认不换行printf format, item1, item2, ...


1、其与print命令的最大不同是,printf需要指定format

2format用于指定后面的每个item的输出格式;

3printf语句不会自动打印换行符;\n


format格式的指示符都以%开头,后跟一个字符;如下

%c: 显示字符的ASCII码;

%d, %i:十进制整数;

%e, %E:科学计数法显示数值;

%f: 显示浮点数;

%g, %G: 以科学计数法的格式或浮点数的格式显示数值;

%s: 显示字符串;

%u: 无符号整数;

%%: 显示%自身;


修饰符

N: 显示宽度;

-: 左对齐;

+:显示数值符号;


eg:

#   awk 'BEGIN{num1=10;printf "%d\n",num1}'

# awk 'BEGIN{num1=10;num2=20;printf  "%d %d\n",num1,num2}'

# awk -F: '{printf "%-20s  %s\n",$1,$NF}' /etc/passwd对齐方式,-20左对齐,20右对齐

输出重定向

基本格式

   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


eg# awk -F: '{printf "%-15s  %i\n",$1,$3 > "/dev/stderr" }' /etc/passwd


小结:

   上述是在学习过程中,总结的笔记和一些示例,在后期的复习过程中会不断的新增内容,调整版面格式。这里,鼓励下自己。



Version: 1.1