awk 参数:
ARGC 命令行参数的个数
ARGV: 命令行参数数组
ARGIND 当前被处理文件的ARGV标志符
NR 已经读出的记录数
FNR 当前文件的记录数
FS 输入字段分隔符(缺省为:space:),相当于-F选项
OFS输出字段分隔符(缺省为:space:)
NF:当前记录中的字段个数
RS:输入记录分隔符,缺省为"\n"
ORS:输出记录分隔符,缺省为换行符,控制每个print语句后的输出符号
awk读取shell中的变量:可以使用-v选项实现功能
FIELDWIDTHSL:设置输入字段宽度的空白分隔字符串(如下面的时间格式转换)
echo "20120905"|awk 'BEGIN{FIELDWIDTHS="4 2 2";OFS="-"}{print $1,$2,$3} '
$1=$1可以使OFS生效,$0=$0可以使FS生效(注意FS设置可以再BEGIN设置)。
[root@node1 ~]# echo '1 1 1
2 2 2' |awk 'NR==1{OFS=":";$1=$1;print}NR==2{OFS="#";$1=$1;print}'
1:1:1
2#2#2
[root@node1 ~]# echo '1 1 1
2 2 2' |awk 'NR==1{OFS=":";print}NR==2{OFS="#";$1=$1;print}'
1 1 1
2#2#2
[root@node1 ~]# echo '1 1 1
2 2 2' |awk 'NR==1{OFS=":";$1=$1;print}NR==2{OFS="#";$1=$1;print}'
1:1:1
2#2#2
[root@node1 ~]# echo '1:1:1
2#2#2' |awk 'NR==1{FS=":";$0=$0;print $1}NR==2{FS="#";$0=$0;print $1}'
1
2
[root@node1 ~]# echo '1:1:1
2#2#2' |awk 'NR==1{FS=":";print $1}NR==2{FS="#";$0=$0;print $1}'
1:1:1
2
awk正则
\Y 匹配一个单词开头或者末尾的空字符串。
\B 匹配单词内的空字符串。
\< 匹配一个单词的开头的空字符串,锚定开始。
\> 匹配一个单词的末尾的空字符串,锚定末尾。
\w 匹配一个字母数字组成的单词。
\W 匹配一个非字母数字组成的单词。
\‘ 匹配字符串开头的一个空字符串。
\' 匹配字符串末尾的一个空字符串。
awk 数组
awk的数组,一种关联数组(Associative Arrays),下标可以是数字和字符串。因无需对数组名和元素提前声明,也无需指定元素个数 。
多维数组,array[index1,index2,……]:SUBSEP是数组下标分割符,默认为“:”。可以事先设定SUBSEP,也可以直接在SUBSEP的位置输入你要用的分隔符
提起AWK数组,下面一个用的类型,很常见:
awk 'NF{a[$1]=a[$1]" "$2;next}END{for(i in a)print i,a[i]}' filename
有时候可能是下面那样,其实效果一样
awk '{a[$1]=a[$1]" "$2}END{for(i in a)print i,a[i]}' filename
NF{...}这段表示非空白行,然后以$1作为数组a的下标,把$2的值赋值给a[$1],然后用END{}这段实行打印出来。
awk函数:
算术函数:
略了吧!很少用。
字符串处理函数:
sub(r,s) 在整个$0中用s替代第一次出现的r,如果成功则返回1,否则返回0,如没有给出t则默认为$0
gsub(r,s) 在整个$0中用s替代r
index(s,t) 返回字符串s中字符串t的第一位置,如果没有字符串t则返回0
length(s) 返回字符串s长度,如果没有给s则返回$0长度
blength (s) 返回字符串s长度(以字节为单位)。如果未给出s参数,则返回整个记录的长度($0 记录变量)。
match(s,r) 如果正则r在s中出现,则返回出现的起始位置,如果没有出现则返回为0,并设置RESTART和RLENGTH值
split(s,a,sep) 使用字段分隔符sep将字符串s分解到数组a的元素中,返回元素个数。如果没有给出sep,则使用FS.数组分隔符和字段分隔采用相同的方式。
sprint(fmt,exp) 返回经fmt格式化后的exp
substr(s,p,n) 返回字符串s中从位置p开始的最大长度为n的子串。如果没有给出n,返回从p开始剩余字符串。
tolower(s) 将字符串s中的大写字符都转换成小写,并返回新串。
toupper(s) 将字符串s中的小写字符都转换成大写,并返回新串。
getline函数:getline函数可以从当前文件,从另一文件,从shell中读取,从管道读取。
getline函数得到下一行当没有改变脚本的控制,可能返回的值为:
1 如果能够读取一行
0 如果到了文件末尾
-1 如果遇到错误
[root@node1 ~]# awk 'BEGIN {printf "enter you name: ";getline name < "-";print name}'
enter you name: gaby
gaby
[root@node1 ~]# awk 'BEGIN {"who am i" | getline;name=$1;FS=":"}name ~ $1{print $NF}' /etc/passwd
/bin/bash
# awk 'BEGIN{while(getline < "/etc/passwd"){print$0;};close("/etc/passwd");}'
system函数
eg1:
cat 1.txt
a b c a d a
s d d d x s a
h j s a s h j h
j d f j a s j k j
要求:删除行内与第一列字符重复的字符,达到这个结果:
a b c d
s d d d x a
h j s a s j
j d f a s k
awk '{a=$1;gsub( a,"");print a$0}' 1.txt |column -t
a b c d
s d d d x a
h j s a s j
j d f a s k
awk '{a=$1;gsub(" ?"a,"");print a$0}' 1.txt
a b c d
s d d d x a
h j s a s j
j d f a s k
第二种在双引号中使用了动态正则
printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。 其中格式化字符串包括两部分内容: 一部分是正常字符, 这些字符将按原样输出; 另一部分是格式化规定字符, 以"%"开始, 后跟一个或几个规定字符,用来确定输出内容格式。
参量表是需要输出的一系列参数, 其个数必须与格式化字符串所说明的输出参数个数一样多, 各参数之间用","分开, 且顺序一一对应, 否则将会出现意想不到的错误。
(1). 可以在"%"和字母之间插进数字表示最大场宽。
例如: %3d 表示输出3位整型数, 不够3位右对齐。
%9.2f 表示输出场宽为9的浮点数, 其中小数位为2, 整数位为6,小数点占一位, 不够9位右对齐。
%8s 表示输出8个字符的字符串, 不够8个字符右对齐。
如果字符串的长度、或整型数位数超过说明的场宽, 将按其实际长度输出.但对浮点数, 若整数部分位数超过了说明的整数位宽度, 将按实际整数位输出;若小数部分位数超过了说明的小数位宽度, 则按说明的宽度以四舍五入输出.另外, 若想在输出值前加一些0, 就应在场宽项前加个0。
[root@node1 ~]# echo "1.5" | awk '{printf ("%f\n",$1)}'
1.500000
[root@node1 ~]# echo "1.5" | awk '{printf ("%.0f\n",$1)}'
2
[root@node1 ~]# echo "1.5" | awk '{printf ("%.1f\n",$1)}'
1.5
[root@node1 ~]# echo "1.5" | awk '{printf ("%2.f\n",$1)}'
2
[root@node1 ~]# echo "1.5" | awk '{printf ("%2.1f\n",$1)}'
1.5
[root@node1 ~]# echo "1.5" | awk '{printf ("%2.1f",$1)}'
1.5[root@node1 ~]# echo "1.5" | awk '{printf ("%.f",$1)}'
(2). 可以在"%"和字母之间加小写字母l, 表示输出的是长型数。
例如: %ld 表示输出long整数
(3). 可以控制输出左对齐或右对齐, 即在"%"和字母之间加入一个"-" 号可说明输出为左对齐, 否则为右对齐。
例如: %-7d 表示输出7位整数左对齐
%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x %X 无符号以十六进制表示的整数
%o 无符号以八进制表示的整数
%g 自动选择合适的表示法
\n 换行
\f 清屏并换页
\r 回车
\t Tab符
\xhh 表示一个ASCII码用16进表示,其中hh是1到2个16进制数
eg1:找出系统中用户名大于五个字符的用户名称:
# awk -F ":" '$1~/^....$/{print $1}' /etc/passwd
# awk -F ":" 'length($1)>4{print $1}' /etc/passwd
eg2:
[root@node1 ~]# cat 1.txt
uid:quota_used_rate
chenmeng:35%
wangfurong:20%
luoxuan:40%
guofeifei:20%
lihui:70%
wangwei:66%
wuhuixiong:44%
shashijie:22%
[root@node1 ~]# cat 2.txt
d:quota_used
wuhuixiong:100m
guofeifei:500m
luoxuan:200m
wangfurong:99m
shashijie:250m
chenmeng:150m
lihui:88m
wangwei:34m
要求写脚本实现如下效果
chenmeng:35%:150m
# awk -F: 'NR==FNR{a[$1]=$NF;next};!/uid/{print $0":"a[$1]}' 2.txt 1.txt
# cat 1.txt |sort >a1;cat 2.txt |sort >b1;join -t ':' a1 b1
这个问题,我也是在网上遇到的,对应第一种方法,重点在于理解NR==FNR{a[$1]=$NF;next}这句,在awk里面输入文件是多个时,NR==FNR才有意义,如果这个值为true,表示还在处理第一个文件。因此这句话的意思就在文件2.txt中生成以用户名为下标的以$NF值为结果的数组a。然后处理文件1.txt,打印出$0和名字对应下标的数组a的值。
第二种情况主要是使用了sort默认排序和join(找出两个文件中,指定栏位内容相同的行,并加以合并,再输出到标准输出设备,注意两个文件内容的排序)的文件合并。
eg3:
[root@node1 ~]# netstat -ant | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
ESTABLISHED 2
LISTEN 17
access.log POST与GET统计
# cat /www/logs/access.log | egrep -o 'GET|POST' | awk '{++method[$NF]} END {for(num in method) print num, method[num]}'
POST 422
GET 18857
eg4
删除文件中所有列都重复的记录
#awk '! a[$0]++' 1.txt
eg5
文件a
220 34 50 70
553 556 32 21
1 1 14 98 33
文件b
10
8
2
要求文件a的每行数据与文件b的相对应的行的值相减,得到其绝对值。
awk '{getline j<"b";for(i=1;i<=NF;i++){$i>j?$i=$i-j:$i=j-$i}}1' a|column -t
210 24 40 60
545 548 24 13
1 1 12 96 31
eg6
文件a
aaa
bbb
ccc
ddd
文件b
111 xxx
222 xxx
333 xxx
444 xxx
要求文件a里的数据依次替换文件b中的xxx字样。
awk '{getline i<"a"}/xxx/{sub("xxx",i,$2)}1' b
111 aaa
222 bbb
333 ccc
444 ddd
####收集各类型网卡###
ifconfig -a |awk -F '[ ]' '{printf $1" "} END{print ""} '
ifconfig -a |grep -Po ".*(?= Link)"