小Q:孤独不是与生俱来的,而是由你爱上一个人的那一刻开始。
============================================================
一:简介
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk做大的优势。
二:调用方式
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk
3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
三:入门实例
1. 只显示/etc/passwd的账户 ==== 查询
#cat /etc/passwd |awk -F ':' '{print $1}' root daemon bin sys
这种是awk+action的示例,每行都会执行action{print $1}。
2. 只显示/etc/passwd的账户和账户对应的shell,而他们之间以tab键分割 分隔符=== OFS
#cat /etc/passwd |awk -F ':' '{print $1"\t"$7}' root /bin/bash daemon /bin/sh bin /bin/sh sys /bin/sh ===#cat /etc/passwd |awk -F ':' '{print OFS=“\t”}{print $1,$7}' ===#cat /etc/passwd |awk -F ':' 'BEGIN{print OFS=“\t”}{print $1,$7}'
3. 如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。 ====== BEGIN END
cat /etc/passwd |awk -F ':' 'BEGIN {print "name,shell"}{print $1","$7} END {print "blue,/bin/nosh"}' name,shell root,/bin/bash daemon,/bin/sh bin,/bin/sh sys,/bin/sh .... blue,/bin/nosh
awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。
4. 搜索/etc/passwd有root关键字的所有行 查询======= '/ ...../ '
#awk -F: '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash
搜索支持正则,例如找root开头的: awk -F: '/^root/' /etc/passwd
5. 搜索/etc/passwd有root关键字的所有行,并显示对应的shell 查询并打印指定的域
# awk -F: '/root/{print $7}' /etc/passwd /bin/bash #这里指定了action{print $7}
四:awk内置变量
awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。
1. 统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容: ===FILENAME
#awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwdfilename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh = awk -F ':''{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd ##特: 使用printf替代print,可以让代码更加简洁,易读 === printf
2. 统计每行共有几个域,打印出每行第几个域;已读第几个域,并依行打印第几个域 == NS NF
3. 将输出内容以一行并用 | 分隔打印 === ORS printf
#awk -F':' '{ORS="|"}{print $1}' /etc/passwd root|bin|daemon|adm|lp|sync|shutdown|halt|mail|news| #==awk -F':' ‘{printf (“%s,”,$1)}’ /etc/passwd #awk -F':' '{print $1}' /etc/passwd root bin daemon adm lp sync shutdown halt mail news
4. 将输出以%格式分隔 === OFS
head /etc/passwd |awk -F':' 'BEGIN{OFS="%"}{print $1,$2}' root%xbin%xdaemon%xadm%xlp%xsync%xshutdown%xhalt%xmail%xnews%x
五:awk的运算
算术运算符
例: awk 'BEGIN{a="b";print a++,++a;}' 0 2
注意:所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0
赋值运算符
= += -= *= /= %= ^= **= 赋值语句
例: a+=5; 等价于:a=a+5; 其它同类
逻辑运算符
|| 逻辑或 && 逻辑与
例: awk 'BEGIN{a=1;b=2;print (a>5 && b<=2),(a>5 || b<=2);}' 0 1
正则运算符
~ ~! 匹配正则表达式和不匹配正则表达式
例: awk 'BEGIN{a="100testa";if(a ~ /^100*/){print "ok";}}' ok
关系运算符
< <= > >= != == 关系运算符
例: awk 'BEGIN{a=11;if(a >= 9){print "ok";}}' ok
注意:> < 可以作为字符串比较,也可以用作数值比较,关键看操作数如果是字符串就会转换为字符串比较。两个都为数字才转为数值比较字符串比较:按照ASCII码顺序比较。
其它运算符
例: awk 'BEGIN{a="b";print a=="b"?"ok":"err";}' ok
awk 'BEGIN{a="b";arr[0]="b";arr[1]="c";print (a in arr);}' 0
awk 'BEGIN{a="b";arr[0]="b";arr["b"]="c";print (a in arr);}' 1
运算级优先级表 级别越高越优先 级别越高越优先
六:awk编程
1. 传递和定义变量+赋值
借助-v 选项,可以将外部值(并非来自stdin)传递给awk:
VAR=10000
echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
另一种传递外部变量方法:
var1="aaa" var2="bbb"
echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
当输入来自于文件时使用:
awk '{ print v1,v2 }' v1=$var1 v2=$var2 filename
以上方法中,变量之间用空格分隔作为awk的命令行参数跟随在BEGIN、{}和END语句块之后。
下面统计/etc/passwd的账户人数
awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd root:x:0:0:root:/root:/bin/bash ...... user count is 40
count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开。
这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0:
awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd [start]user count is 0 root:x:0:0:root:/root:/bin/bash ... [end]user count is 40
2. 条件判断语句
例一. awk分枝结构允许嵌套,其格式为:
if(表达式)
{语句1}
else if(表达式)
{语句2}
else {语句3}
示例:
awk 'BEGIN {
test=100;
if(test>90) {
print "very good"; }
else if(test>60) {
print "good"; }
else{ print "no pass"; } }' very good 每条命令语句后面可以用 ; 分号结尾。
例二. 统计某个文件夹下的文件占用的字节数,过滤4096大小的文件(一般都是文件夹)
ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
[end]size is 8.22339 M
3. 循环语句
例一:while语句
while(表达式)
{语句}
示例:
awk 'BEGIN {
test=100; total=0;
while (i<=test) {
total+=i; i++; }
print total; }' 5050
例二:for循环
for循环有两种格式:
格式1: for(变量 in 数组) {语句}
示例:
awk 'BEGIN {
for (k in ENVIRON) {
print k"="ENVIRON[k]; } }'
TERM=linux
G_BROKEN_FILENAMES=1
SHLVL=1
pwd=/root/text ...
logname=root 注:ENVIRON是awk常量,是子典型数组
格式2:for (变量;条件;表达式) {语句}
示例: awk 'BEGIN {
total=0 ;
for(i=0;i<=100;i++){
total+=i; }
print total; }' 5050
七:数组 字符串 函数
.....................................................................................................................
tips :
1. awk 默认不能直接使用花括号
正则表达式中,有一个用法就是一个字符或者一串字符的重复次数。比如(abc){1,3}
表示含有 abc abcabc abcabcabc 这样的行都会匹配到
awk 直接这样用是匹配不到东西的
awk '/(abc){1,3}/' 1.txt
这是因为在awk中()和{}都有特殊的含义,需要做个特殊处理才可以:
awk --posix '/(abc){1,3}/' 1.txt
2. 在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
推荐:http://www.cnblogs.com/emanlee/p/3327576.html
官方:http://www.gnu.org/software/gawk/manual/gawk.html