awk 简介

• awk是 3 个姓氏的首字母,代表该语言的 3 个作者
• awk的版本有很多,包括: 旧版 awk,新版 awk(nawk), GNUawk(gawk)等
• awk程序有 awk命令、括在引号或写在文件中的指令以及输入文件这几个部分组成

从文件输入

• 格式:
–gawk '/匹配字符串/' 文件名
–gawk '{处理动作}' 文件名
–gawk '/匹配字符串/ {处理动作}' 文件名
实例:
[root@desktop243 Desktop]# gawk -F: '/student/{print $3}' /etc/passwd

#-F:以":"号为分隔符分割出参数
[root@desktop243 Desktop]# gawk -F: '/student/{print $1,$3}' /etc/passwd
student
[root@desktop243 Desktop]# gawk -F: '/student/{print $0}' /etc/passwd
student:x::::/home/student:/bin/bash

awk 工作原理

以下面的内容的 names 文件名举例按步骤解析 awk 的处理过程
[root@desktop243 Desktop]# vim names
Tome Savage
Molly Lee
John Doe
编辑这个 names文件时,Tome 行是多个出来空格,Molly 行是一个出来空格,John 是空格键打出来的空格。使用下面 awk命令处理
cut 无法识别空格键和<Tab>打出来的空格
[root@desktop243 Desktop]# cat names | cut -d ' ' -f
Tome
Molly Lee
John
[root@desktop243 Desktop]# cat names | cut -d ' ' -f
Savage
Doe
gawk能区分空格键和<Tab>打出来的空格,“,”是代表打印时$ 和$ 之间有空格
[root@desktop243 Desktop]# gawk '{ print $1,$3}' names
Tome
Molly
John
第一步:awk对文件或管道的内容一次只处理一行,将获取到
的这一行赋给内部变量 $0

第二步:这一行的内容按 awk内部变量 FS 定义的分隔符,缺省为空格(包括 tab 制表符)分解成字段,每一段存储在从 $1 开始的变量中

第三步:awk中 print 命令打印字段
–{print $1,$3} #只取有用的第一段和第三段
–在打印时$1 和$3 之间由空格间隔。
","逗号是一个映射到内部的输出字段分隔符(OFS),OFS 变量缺省为空格,逗号在输出时被空
格替换
Tome 100
Molly 200
John 300
• 接下来,awk处理下一行数据,直到所有的行处理完
实例:
OFS,输出字段分隔符定义为两个制表符,“,”在输出时被制表符替换
[root@desktop243 Desktop]# gawk '{ OFS="\t\t";print $1,$3}' names
Tome
Molly
John

从命令输入

• awk还可以处理通过管道接收到的 Linux 命令的结果,shell程序通常使用 awk 做深处理
• 格式:
–命令 | gawk '/匹配字符串/'
–命令 | gawk '{处理动作}'
–命令 | gawk '/匹配字符串/ {处理动作}'
df | gawk '$4 > 200000' #剩余空间大于 200000 的磁盘
[root@desktop243 Desktop]# df | gawk '$3 > 100'
Filesystem 1K-blocks Used AvailableUse% Mounted on
% /
tmpfs % /dev/shm
/dev/sda1 % /boot
% /home

格式化输出 print 函数

awk命令操作处理部分是放在 "{}"(括号)中
print 函数将变量和字符夹杂着输出,如同 linux 中的 echo 命令
[root@desktop243 Desktop]# date
Sat Oct :: CST
[root@desktop243 Desktop]# date | gawk '{print "Month: "$2"\nYear:",$6}'
Month: Oct
Year:
注意上面的例子,一种是直接在Month空格后连接$2,另一种是在Year和$6 之间使用了逗号,都由 OFS 决定

OFMT 变量

在 OFMT 中定义数字的格式
模拟分区大小的转换,保留小数点后  位:
[root@desktop243Desktop]#echo -e "/dev/sda1\t1234325\n/dev/sda3\t2209"\
> | gawk '{OFMT="%.2f";print $1":",$2/1024,"M"}'
/dev/sda1: 1205.40 M
/dev/sda3: 2.16 M
#$2/1024 前后必须要有","作为分隔定义,如果没有其中一个就会不能实现打印小数点后 2
默认为"%.6gd",只会打印 6 位

[root@desktop243Desktop]#echo -e "/dev/sda1\t1234325\n/dev/sda3\t2209"\
|gawk '{prrnt $1":",$2/1024,"M"}'
/dev/sda1: 1205.4 M
/dev/sda3: 2.15723 M

printf 函数转义字符

printf 与 C 语言中的 printf 雷同
–转义字符
[root@desktop243 Desktop]# cat names
Tome Savage
Molly Lee
John Doe
names 文件中第 列的第一个字符:-%c 字符
[root@desktop243 Desktop]# gawk '{printf("The charcter is %c\n",$2)}' names
The charcter is S
The charcter is L
The charcter is D
names 文件中第 列的字符串:–%s 字符串
[root@desktop243 Desktop]# gawk '{printf("The string is %s\n",$2)}' names
The string is Savage
The string is Lee
The string is Doe
打印一个人的名字和年龄:–%d 十进制整数
规定好了是字符串或者整数,后面的变量就必须是与之匹配的类型,否则会出错。
[root@desktop243 Desktop]# echo "yangwawa 10"|gawk \
> '{printf("%s is %d years old.\n",$1,$2)}'
yangwawa is years old.
–%f 浮点数
[root@desktop243 Desktop]# echo "yangwawa 10 155"|gawk\
> '{printf("%s is %d years old,his heigth si %.2fm.\n",$1,$2,$3/100)}'
yangwawa is years old,his heigth si 1.55m.

printf 函数修饰符

打印时需要对齐,下面提供一些打印输出时所用到的修饰符
-(横杠) 左对齐和右对齐(默认),加| |是为了突出长度和对齐效果:
[root@desktop243 Desktop]# echo "Bluefox" | gawk '{printf("Welcome to \
> |%s| lab\n",$1)}'
Welcome to |Bluefox|lab
[root@desktop243 Desktop]# echo "Bluefox" | gawk '{printf("Welcome to\
> |%10s|lab\n",$1)}'
Welcome to | Bluefox|lab
[root@desktop243 Desktop]# echo "Bluefox" | gawk '{printf("Welcome to
> |%-10s|lab\n",$1)}'
Welcome to |Bluefox |lab
#(井号) 显示 8 进制时前面加 0,显示 16 进制时加 0x
+(加号) 显示正负值时的正+负-号
0(零) 用 0 对显示值填充空白处
练习:将文件(之前很乱的)names整理并保存,要求每一行每一列都要对齐:
[root@desktop243 Desktop]# gawk '{printf("%s\t\t%s\t\t%d\n",$1,$2,$3)}' \
>names > name ;rm -f names ;mv name names
[root@desktop243 Desktop]# cat names
Tome Savage
Molly Lee
John Doe

文件中的 awk 命令

• 将 awk写入一个文件中,更适合复杂的程序
• 使用 -f 选项指定 awk的文件名
• awk一次读取一条记录,测试文件中的每一条命令这样循环
根据下面显示结果分析代码:
执行结果:
[root@desktop243 Desktop]# cat names | gawk -f abc.awk
________--------________
Nice to meet you -->Molly
________--------________
________--------________
John
代码:
[root@desktop243 Desktop]# cat abc.awk
#!/bin/gawk
/^[Mm]olly/{print "Nice to meet you -->"$}
{print "________--------________"}
$> {print $}
被测试的文件:
[root@desktop243 Desktop]# cat names
Tome Savage
Molly Lee
John Doe
分析:
程序开始后首先读到的$ 是 Tome Savage ,开始的字符既不是 M 也不是m, 后 面 的 {print "Nice to meet you -->"$}不 会 执 行 , 执 行 {print "________
--------________"}后,判断 100 不大于 200,则 {print $1}不执行;接着$0 是 Molly
Lee ,首字符串匹配,执行{print "Nice to meet you -->"$}的结果是
Nice to meet you -->Molly,然后执行下一句,执行最后一句时发现 不大于 ,
{print $}不执行;最后传给$0的是John Doe ,第一句由于不匹配而没有
执行,执行完第二句代码,最后 大于 ,所以执行{print $},结果是显示 John。
小小地修改一下代码:
#!/bin/gawk
/^[Mm]olly/{print "Nice to meet you -->"$;\
print "________--------________"}
$> {print $}
再测试,结果:
[root@desktop243 Desktop]# gawk -f abc.awk names
Nice to meet you -->Molly
________--------________
John

记录与字段

记录分隔符:默认行输入和输出的分隔符都是回车 ,保存在 RS 和 ORS 内部变量中
实例:
默认:
[root@desktop243 Desktop]# gawk '{print $1,$2}' names
Tome Savage
Molly Lee
John Doe
自定义:
[root@desktop243 Desktop]# gawk 'ORS="\n+-+\n"{print $1,$2}' names
Tome Savage
+-+
Molly Lee
+-+
John Doe
+-+
变量$0: awk每次一行取得整条记录,$0 随之改变,同时内部变量 NF(字段的总数,即列数)也随之变化
实例:添加一个只有 2 列的数据,测试 NF:
[root@desktop243 Desktop]# echo "Mayy Daly" >> names
[root@desktop243 Desktop]# gawk '{print NF,$0}' names
Tome Savage
Molly Lee
John Doe
Mayy Daly
变量 NR: 每条记录的行号,处理完一行将会加 1,所以全部处理完后可以理解成行数的总数
[root@desktop243 Desktop]# gawk '{print NR,": ->",$0}' /etc/passwd
: -> root:x:::root:/root:/bin/bash
: -> bin:x:::bin:/bin:/sbin/nologin
…… ……
: -> student:x::::/home/student:/bin/bash
: -> visitor:x::::/home/visitor:/bin/bash

字段分隔符

• FS 内部变量:
– 保存着输入字段的分隔符的值 (OFS 则代表输出的分隔符)
– 默认使用空格或制表符来分隔字段
– 在 BEGIN 语句段中设置 FS 的值
实例:
[root@desktop243Desktop]# cat /etc/passwd | gawk 'BEGIN{FS=":";print"--count
normal user now--"}$3 >= 500 { print $1;count++} END {printf("Total : %d
Normal users\n",count)}'
--count normal user now--
nfsnobody
student
visitor
Total : Normal users
也可以在命令行中指定 -F 选项改变分隔符
默认是以空格为分隔符
[root@desktop243 Desktop]# gawk 'NR <= 4 {print NR,$1}' /etc/passwd
root:x:::root:/root:/bin/bash
bin:x:::bin:/bin:/sbin/nologin
daemon:x:::daemon:/sbin:/sbin/nologin
adm:x:::adm:/var/adm:/sbin/nologin
指定分隔符为“:”
[root@desktop243 Desktop]# gawk -F : 'NR <= 4 {print NR,$1}' /etc/passwd
root
bin
daemon
adm
• 使用多个字符分隔符,写在括号中,下面的例子使用空格,冒号和制表符
– gawk -F'[ :\t]' '{print $1, $5, $7 }' /etc/passwd

模式

awk模式用来控制输入的文本行执行什么样的操作

• 模式为正则表达式
• 模式具有着隐式 if 语句
• 模式写在模式操作符两个 "//"中
实例:
[root@desktop2 Desktop]# gawk '/^root/' /etc/passwd
root:x:::root:/root:/bin/bash
[root@desktop2 Desktop]# gawk '/^root/ || /^student/' /etc/passwd
root:x:::root:/root:/bin/bash
student:x::::/home/student:/bin/bash
[root@desktop2 Desktop]# gawk -F: '/student/{print $1":"$3}' /etc/passwd
student:
[root@desktop2 Desktop]# gawk '/^sshd/,/^stude*/' /etc/passwd
sshd:x:::Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
nslcd:x:::LDAP Client User:/:/sbin/nologin
tcpdump:x::::/:/sbin/nologin
pulse:x:::PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
gdm:x::::/var/lib/gdm:/sbin/nologin
student:x::::/home/student:/bin/bash

操作

• 格式
模式 { 操作语句 1; 操作语句 2; ...... ;}
• 或者
模式 { 操作语句 1 操作语句 2 ...... }

正则表达式

• 很多地方都是用到正则表达式来匹配特定的信息
^ 串首
$ 串尾
. 匹配单个任意字符
* 匹配零个或多个前面的字
+ 匹配一个或多个前面的字符
? 匹配零个或一个前面的字符
[ABC] 匹配括号中给出的任一个字符
[A-Z] 匹配 A到 Z之间的任一个字符
A|B 匹配二选一,或者的意思,等同于[AB]
(AB)+ 匹配一个或多个括号中的组合
\* 星号本身,转义星号本身

匹配操作符

• 前面介绍了模式,也可以对特定的列使用模式匹配符"~",与条件做比较
• 语法:
• ~//
或者
!~ / /
[root@desktop2 Desktop]# gawk -F: '$1 ~ /[sS]tud*/{print $1":"$3}' /etc/passwd
student:

POSIX 字符类表达式

[[:allnum:]] 字母和数字字符 [A-Za-z0-9]
• [[:alpha:]] 字母字符等同于[A-Za-z]
• [[:cntrl:]] 控制字符
• [[:digit:]] 数字字符 [0-9]
• [[:graph:]] 非空白字符(空格,控制字符等)
• [[:lower:]] [[:upper:]] 小写/大写字母
• [[:space:]] 所有的空白字符(换行符,空格,制表符)
一般不会用这些,这些不好记。
gawk 'BEGIN { FS=":"} $1 ~ /^[[:digit:]]+$/ {print $0 }' /etc/inittab
 

awk 脚本

• 如果有多条 awk的模式或指令要处理,将它们都写在脚本中
• #为注释符
• 一行多条命令要用分号隔开
• 操作跟在模式之后的话,必须一行书写完(即左大括号在同一行)
[root@desktop2 Desktop]#vim info
#!/bin/gawk
# The first awk script
/student/ { print "Studentid is" , $}
/vistor/ {print "vistor id is", $}
运行:
[root@desktop2 Desktop]#gawk -F: -f info /etc/passwd

比较表达式

用来对文本做比较,只有条件为真,才执行指定的动作
• < gawk '$3 < 500' /etc/passwd #系统帐户
• <= gawk '$3 <= 499' /etc/passwd #同上
• == gawk '$3 == 0' /etc/passwd #id 为 0,root 帐户
• != gawk '$3 != 500' /etc/passwd #非 id=500 的帐户
• >= gawk '$3 >= 500' /etc/passwd #普通帐户
• > gawk '$3 > 499' /etc/passwd #同上
• ~ gawk '$1 ~ /^root/' /etc/passwd #root 帐户
• !~ gawk '$1 !~ /^root/' /etc/passwd #非 root 帐户

条件表达式

• 格式:条件表达式 1?表达式 2:表达式 3
• 与之等同的代码段如下
{
if (条件表达式 1 成立)
表达式 2
else
表达式 3
}
实例:
[root@desktop2Desktop]#echo "111 333"| gawk '{max=$1>$2?$1:$2;print max}'

[root@desktop Desktop]# cat /etc/passwd | gawk -F: '{printf("%s is %s
user\n",$1,$3 >= 500?"Normal":"System") }'
rootis System user
bin is System user
…… ……
student is Normal user
visitor is Normal user

算术运算

可以在模式中执行计算操作
awk '$3 / 1024 > 2000' filename
+ 加 10+2 =12
- 减 10-2 =8
* 乘 10*1024 =10240
/ 除 10240/1024 =10
% 求模(求余数) 10%3=1
^ 次方 2^3=8

逻辑操作符

逻辑操作符用来测试模式的真假
&& 逻辑与 1&&0 FALSE
|| 逻辑或 1 || 0 TRUE
! 逻辑非 !0 TRUE
awk -F: '$3 >500 && $3 <= 550' /etc/passwd
awk -F: '$3 ==100 || $3 > 50'

范围模式

范围模式提供了选择一段数据操作的可能
• 先匹配第一个模式,将作为开始部分
• 接着匹配第二个模式,作为结束
• 之间的这一段将选中做操作
• 模式与模式之间使用","逗号间隔
awk '/operator/,/nobody/' /etc/passwd

验证数据的有效性

验证数据的有效性可以综合我们之前所学的判断方式
• 判断有效数据是否为七列,可以通过检测 NF 内部变量
实例:找出 employees数据表中的缺空数据
[root@shiyan ~]# cat employees
Name Numbers Time Price
Tome //
Marry //
Molly //
John //
Tome //
Molly //
John //
[root@shiyan ~]# gawk 'NF !=4 {print NR,": has only",NF,"fileds"}' employees
: has only fileds
: has only fileds
• 判断是否为字母开头
awk '$1 ~ /^[a-zA-z]+/ {.....}' filename
• 判断数值是否大于某值
awk '$4 > 200 {......}' filename

数值变量和字符串变量

字符串写下双引号中,比如"Hello world"
• 默认将一个字符串转化成数字时,将变成 0
–name = "Nancy" #name 此时为字符串
–x++ #x 是数字,初始值为 1
–number = 35 #number 是数字
• 强行转化
–name + 0 #name 此时变成数字 0
–number " " #number 此时为字符

用户自定义变量

变量名可以是字母数字和下划线组成,但不能以数字开头。
• awk将字符串变量初始化为空字符串 ""
• 数值变量初始化为 0
• 格式
–变量 = 表达式
[root@sya ~]#gawk'$1~/^T/{wage=$2*$4;print$1,$3,"wage:",wage}' ./employees
Tome // wage:
Tome // wage:

BEGIN 模式

BEGIN 模式后面跟了一个程序段
• 对输入文件进行任何处理之前,先执行 BEGIN 程序段
• 用来修改内部变量(OFS,RS,FS)等的 值
• 用来初始化用户变量和打印标题等
[root@shiyan ~]# gawk 'BEGIN{FS=":";OFS="\t\t";ORS="\n****\n"} NR >=20 &&
NR <= {print $,$NF}' /etc/passwd
smmsp /sbin/nologin
****
nscd /sbin/nologin
****
oprofile /sbin/nologin
****
pcap /sbin/nologin
****
[root@desktop1 Desktop]# echo "$(date +%F)" | gawk 'BEGIN{FS="-";} \
> { print $"/"$"/"$}'
//
甚至无需文件名
[root@shiyan ~]# gawk 'BEGIN{print "Hello World"}'
Hello World

END 模式

不匹配任何输入行
• 在 awk处理完输入行之后执行
[root@shiyan ~]# gawk 'END{print "Total user:",NR}' /etc/passwd
Total user:
实例:查看虚拟主机有几台:
[root@shiyan ~]#gawk '/^<Virt/ { total++ } END { print total, virtual hosts }'
/etc/httpd/httpd.conf
virtual hosts

输出重定向

可以将 awk 的输出重定向到 Linux 文件中
• 目标文件必须用双引号括起来
• "> " 清空文件,写入 awk信息,awk程序执行完毕后才关闭文件
• ">>" 追加内容
实例:将 employees 文件中的错误数据向屏幕输出,正确数据则将每个人每天的总金额输出到/root/cc 文件中:
[root@shiyan ~]# vim rw.awk
#!/bin/gawk
{ \
if ( NF != ) \
{ \
print "Line",NR,":missing some info" \
}else{ \
print $,"saled:",$*$ > "/root/cc"\
} \
}
测试:
[root@shiyan ~]# gawk -f rw.awk employees
Line :missing some info
Line :missing some info
[root@shiyan ~]# cat cc
Tome saled:
Marry saled:
Molly saled:
John saled:
John saled:

输入重定向-读输入 getline

从标准输入,管道或文件中读取输入
• 读取每一行,重置 NF,NR 和 FNR 内部变量
• 有内容读取到,返回 1 (为真值)
• 读到 EOF(文件末尾) 返回 0 (为假值)
• 发生错误,返回 -1
[root@shiyan ~]# gawk 'BEGIN{"date"| getline DATE}{print DATE,$1,$7}'
/etc/passwd
年 月 日 星期六 :: CST root:x:::root:/root:/bin/bash
年 月 日 星期六 :: CST bin:x:::bin:/bin:/sbin/nologin
…… ……
[root@shiyan ~]# gawk 'BEGIN{"date +%F"| getline DATE}{print DATE,$1,$7}'
/etc/passwd
-- root:x:::root:/root:/bin/bash
-- bin:x:::bin:/bin:/sbin/nologin
…… ……
实例:提示用户输入一个用户名,判断该用户是在/etc/passwd 中的哪一行:
[root@shiyan ~]# gawk 'BEGIN{print"What is your name?";\
>getline name < "/dev/tty"}\
>$ ~ name{print "Found",name,"online",NR".";\
>print"NIce to meet you",name,"@_@"}' /etc/passwd
Whatis your name?
student #getline 是重定向到终端接受的
Found student online .
NIce to meet you student @_@

Bash 向 awk 发送参数

getline 函数也可以从 Bash 命令发送的管道中获取参数
• 语法:
–getline 变量 < "-" # "-" 如同 tar 一样代表着管道过来的信息
[root@shiyan ~]# echo "$(date +%F)"|gawk 'BEGIN{ FS=":";\
>getline D < "-"}NR>={print D" "$"/"$":"$}' /etc/passwd
-- avahi-autoipd/:/sbin/nologin
-- student/:/bin/bash
-- visitor/:/bin/bash
-- oracle/:/bin/bash

管道

打开管道的前提是其他管道必须关闭,每次只能打开一个管道,这和 Linux 中一条命令无
限次的使用管道不同
• 管道右边的命令必须写在双引号之间
[root@shiyan ~]# gawk '/^[^#:]+/{print $1}' /etc/hosts
127.0.0.1
172.24.205.191
172.24.200.254
172.24.254.254
[root@shiyan ~]# gawk '/^[^#:]+/{print $1 |"ping -c2 "$1}' /etc/hosts
PING 127.0.0.1 (127.0.0.1) () bytes of data.
bytes from 127.0.0.1: icmp_seq= ttl= time=0.028 ms
connect: Network is unreachable
connect: Network is unreachable
connect: Network is unreachable
bytes from 127.0.0.1: icmp_seq= ttl= time=0.037 ms
--- 127.0.0.1 ping statistics ---
packets transmitted, received, % packetloss, time 999ms
rtt min/avg/max/mdev = 0.028/0.032/0.037/0.007 ms

关闭文件和管道

要对 awk 程序中的某个文件或管道多次读写,得先关闭程序
• awk程序在处理文件时会保持打开状态直到脚本结束。
• END 块中也受管道影响。
• 关闭文件或管道时的引号中的内容与打开文件或管道时的名称
一致,甚至包括参数,空格
• 使用 close()函数实现
gawk '/^[^#]+/ { print $1 | "ping -c3 " $1 } END {close("ping -c 3 ")}' /etc/hosts

system 函数

• system()函数以 Linux 命令作为参数
• 执行 Linux 命令之后将 Linux 命令 $? 退出值返回给 awk
• 注意:函数中 Linux 命令必须用双引号
[root@desktop1 Desktop]# gawk '/^[^#:]/{ if(system("ping -c2 "
$" > /dev/null")== ){print $" is on line"}else{ print $" is down"}}' /etc/hosts
127.0.0.1 is on line
172.24.0.2 is down
172.24.200.254 is on line
172.24.254.254 is on line 注意里面的空格“ ” !

if 语句

• awk就如 C 语言,有着变量,条件判断和循环
• if 语句是条件判断的关键字,默认为隐藏,
• 格式
if (判断的表达式)
{
语句 1;语句 2;…… #判断表达式(为真)成立而执行的代码段
}
实例:
1、gawk -F: '{if( $3 >= 500) print $1 "is a normal user\n"}'/etc/passwd
2、 gawk -F: '{ if ($3 >=500) {count++;} } END { print "Total normal user: "count }' /etc/passwd
 

if/else 语句

• if/else 语句实现了真与假的两重处理
• 判断表达式为 1(真),与前面 if 语句相同
• 为 0 (假)则执行 else 后面的代码段
• 格式:
if (判断表达式) {
语句 1;语句 2;…… #判断表达式成立
} else {
语句 10,语句 11;…… #判断表达式不成立
}
实例 1:
gawk -F: '{ if($3 >=500) { print $1 "is a normal user\n" } else { print $1 "is
a system user\n"}' /etc/passwd
实例 2:
gawk -F: '{ if($3 < 500) { print $1 "is a system user\n" } else { print $1 "is a
normal user\n"}' /etc/passwd
 

if/else 和 else if 语句

• 如果在计算多重判断的时候,我们还需要对 if/else 语句做扩充,在其后再加上 if else,做
下一个判断
语法
if (判断表达式 1) {
语句 1; 语句 2;…… #表达式 1 成立
}else if (判断表达式 2) {
语法 10;语法 11;...... #表达式 2 成立
}else if (判断表达式 N...) {
语法 N0;语法 N1;…… #表达式 N 成立
}else {
语法 Y1;语法 Y2;.... #以上都不成立
}

while 循环

首先给初始一个变量,接着在 while 判断表达式中测试该变量,为 0(假)退出 while 循环;
• 注意:代码段中要在一些情况下修改初始的变量值,否则是一个消耗 CPU 的死循环
• 语法
while(条件判断式){
语句 1;语句 2;…… # 语句成立一直执行部分
}
[root@desktop Desktop]# gawk -F: '{print NR,":User info:\n======";i=1;
while(i<=NF){print $i;i++};print "\n"}' /etc/passwd
:User info:
======
root
x root
/root
/bin/bash
…… ……
:User info:
======
visitor
x /home/visitor
/bin/bash

for 循环

有着三个表达式,第一个为初始化变量,第二个做测试,第三个用来改变初始变量(如果缺少
此部分,就得到代码段修改,否则是死循环)
• 语法
for(初始表达式; 判读表达式; 更新表达式) {
语法 1; 语法 2; .....
}
[root@desktop Desktop]# gawk -F: '{print NR,":User info:\n======";
i=;for(;i<=NF;i++){print $i};print "\n"}' /etc/passwd
:User info:
======
root
x root
/root
/bin/bash
:User info:
======
bin
x bin
/bin
/sbin/nologin
…… ……

循环控制

break 用来终止循环
• continue 语句 用来不做后续操作,绕过此次循环,继续下一循环
实例:
为了方便实验,创建一个/tmp/passwd:
[root@localhost ~]# cat /tmp/passwd
avahi-autoipd:x:::avahi-autoipd:/var/lib/avahi-autoipd:/sbin/nologin
student:x::::/home/student:/bin/bash
visitor:x::::/home/visitor:/bin/bash
harry:x::::/home/harry:/bin/bash
[root@desktop Desktop]# gawk -F: '{i=1;
while(i++ < NF ){
if($i~/daemon/)
{print NR,$;break;}
}
}' /etc/passwd
daemon
haldaemon
avahi
continue 语句:会将匹配的这行其他段打印出来,继续往下查询
[root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;
while(i++ < NF){if($i~/student/){ print "========";continue; }
else { print $i ;}}}'
avahi-autoipd
x avahi-autoipd
/var/lib/avahi-autoipd
/sbin/nologin
========
x ========
/bin/bash
visitor
x /home/visitor
/bin/bash
harry
x /home/harry
/bin/bash
break 语句:匹配的这行其他段都不会打印,继续往下查询
[root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;
while(i++ < NF){if($i~/student/){ print "========";break; }
else { print $i ;}}}'
avahi-autoipd
x avahi-autoipd
/var/lib/avahi-autoipd
/sbin/nologin
========
visitor
x /home/visitor
/bin/bash
harry
x /home/harry
/bin/bash

next 语句

在循环处理时,使用 next 语句,将会使 awk 中跳过 next 段
以后本次的处理,执行下一个循环
• 下面的例子将打印出除系统帐户以外的所有用户
[root@desktop18 Desktop]# gawk -F: '{if($3<500){next;}else{print $1}}'
/etc/passwd
nfsnobody
student
visitor

exit 语句

exit 用来终止 awk 对后续内容的处理
• exit 也可以返回具体的值,提供 Bash 做状态判断
• 要注意,exit 退出不会绕过 END 块,换句话说 END块
总会执行,对于要向 BASH 返回值的处理,使用以下的方法

• 语法:
–{ exit(1) }
实例:
exit,找到匹配的就会退出,返回 ,不再往下查询:
[root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;while(i++ <
NF){if($i~/student/){ print "========";exit(); } else { print $i ;}}}'
avahi-autoipd
x avahi-autoipd
/var/lib/avahi-autoipd
/sbin/nologin
========
[root@localhost ~]# echo $?

关联数组的下标

• awk中的数组下标可以是数字,也可以是字符串
• 数组和变量一样,需要的时候直接创建
• 数组的下标数值由 0 开始
[root@desktop18 Desktop]# vim employess
Tom //
Mary //
Bill //
Mary //
Tom //
[root@desktop18 Desktop]# gawk '{ name[k++]=$1} END{for(i=0;i<NR;i++){
printi,name[i]}}' employess
Tom
Mary
Bill
Mary
Tom

用字符串作为数组的下标

• 专门用于数组的 for 循环,遍历数组
• for(索引 in 数组)
{
–语句
}

打印出用户名和总工资:数组下标:字符串
将用户名($)相同的行的工资($)相加
[root@desktop18 Desktop]# gawk '{ name[$1]+=$4} END{for(Name in name){
print Name,":",name[Name]}}' employess
Tom :
Mary :
Bill :

处理命令行参数

从命令行获得参数,ARGC代表参数的总数,ARGV数组用来保存输入的参数
[root@desktop18 Desktop]# vim argvs
#!/bin/gawk
BEGIN{\
for ( i=;i < ARGC ; i++ )\
{ \
printf( "ARGV[%d] is --> %s\n",i,ARGV[i])\
}\
printf( "Total : %d parameters\n",ARGC);\
}
[root@desktop18 Desktop]# gawk -f argvs /etc /root 172.24.200.254
ARGV[] is --> gawk
ARGV[] is --> /etc
ARGV[] is --> /root
ARGV[] is -->
ARGV[] is --> 172.24.200.254
Total : parameters
awk不会把 -f 以及后面的脚本认定为参数
[root@desktop18 Desktop]# gawk -f argvs /etc "ls /root"
ARGV[] is --> gawk
ARGV[] is --> /etc
ARGV[] is --> ls /root
Total : parameters
用 xargs来接收保存命令传来的参数并传递:(以空隔来分别参数)
[root@desktop18 Desktop]# echo "172.24.200.254" | xargs ping -c2
PING 172.24.200.254 (172.24.200.254) () bytes of data.
From 192.168.117.167 icmp_seq= Destination Host Unreachable
From 192.168.117.167 icmp_seq= Destination Host Unreachable
--- 172.24.200.254 ping statistics ---
packets transmitted, received, + errors, % packetloss, time 3000ms
pipe
[root@desktop18 Desktop]# echo "172.24.200.254 /etc/passwd /root" | xargs
gawk -f argvs
ARGV[] is --> gawk
ARGV[] is --> 172.24.200.254
ARGV[] is --> /etc/passwd
ARGV[] is --> /root
Total : parameters

字符串 sub 和 gsub 函数

sub 和 gsub 函数,可以在条目中查找与给定的正则表达式匹配的字符串,并取代它
• sub 和 gsub 的区别是,前者只对匹配部分一次替换,后者为全部替换
• 语法:
–sub( 正则表达式 , 替换字符串) #默认为$0,整条记录
–sub( 正则表达式,替换字符串 , 目标字段); #指定的字段
换名字:
[root@desk18Desktop]# gawk '{sub(/[Tt]om/,"ttooomm",$1);print $0}' employess
ttooomm //
Mary //
Bill //
Mary //
ttooomm //
sub:只对匹配部分一次替换
[root@desktop18 Desktop]# gawk '{sub(/0/,"kkkkk");print $0}' employess
Tom 2kkkkk08//
Mary 2kkkkk08//
Bill 2kkkkk09//
Mary 2kkkkk09//
Tom 2kkkkk09//
gsub 全部替换
[root@desktop18 Desktop]# gawk '{gsub(/0/,"kkkkk");print $0}' employess
Tom 2kkkkkkkkkk8/kkkkk3/kkkkk5
Mary 2kkkkkkkkkk8/kkkkk4/kkkkk6
Bill 2kkkkkkkkkk9/1kkkkk/kkkkk9
Mary 2kkkkkkkkkk9/1kkkkk/
Tom 2kkkkkkkkkk9//1kkkkk

sub 函数示例

• 注意正则表达式的使用方法
• gawk '{ sub(/172\.168\.0\./, "192.168.0." ); print}'/etc/sysconfig/iptables
• gawk '{ sub(/Mac/,"MacIntosh",$1) ; print }' filename
• gawk '{ gsub(/[Tt]om/, "Thomas" , $1); print }' datafile

字符串长度 length 函数

• length 函数取回字符串的字符数量
• 格式
–length(字符串)
–length #不带参数,返回记录中的字符个数
带参数:
[root@desktop18 Desktop]# echo "123qwe" | gawk 'BEGIN{getline RR <"-";print
length(RR)}' [root@desktop18 Desktop]# gawk '{print $1,length($1)}' employess
Tom
Mary
Bill
Mary
Tom
不带参数:
[root@desktop18 Desktop]# gawk '{print $1,length}' employess
Tom
Mary
Bill
Mary
Tom

字符 substr 函数

• substr函数返回从字符串指定位置开始的一个子字符串。
• 如果指定了子字符串的长度,返回字符串的对应的部分
• 语法:
–substr(字符串,起始位置)
–substr(字符串,起始位置,子字符串长度)
[root@desktop18 Desktop]# gawk '{print substr($1,2,length)}' employess
om
ary
ill

ary

om

[root@desktop18 Desktop]# gawk '{print substr($3,1,4)}' employess

2008

2008

2009

2009

2009

将 employess 中的日期换成另一种格式

[root@desktop18 Desktop]# gawk '{print $1,$2,

substr($3,9,2)"/"substr($3,6,2)"/"substr($3,1,4),$4}' employess

Tom 234 05/03/2008 685

Mary 451 06/04/2008 932

Bill 127 09/10/2009 3456

Mary 341 18/10/2009 4532

Tom 465 10/11/2009 3421
 

字符 match 函数

• match 函数根据正则表达式返回其在字符串中出现的位置,未出现,返回 0
• match 函数中变量
RSTART 子字符串出现的起始位置
RLENGTH 子字符串的长度
而这些变量之后可以提供给 substr 来提取子字符串
实例:文件中的时间格式不同的情况下需要提取年份
[root@desktop18 Desktop]# gawk '{print $3}' employess --
--
//
--
--
[root@desktop18 Desktop]# gawk '{match($3,/[12][0-9][0-9][0-9]/);
print $,substr($,RSTART,RLENGTH)}' employess
Tom
Mary
Bill
Mary
Tom

字符 split 函数

• split 函数用来将一个字符串拆分成一个数组
• 语法:
–split(字符串, 保存数据的数组,字段分隔符)
#注意 Split 函数切割的数组下标从 1 开始,0 永远为空
–split(字符串, 保存数据的数组 ) #使用 FS 默认值
[root@desktop18 Desktop]# cat database
-- car
-- car
-- dog
-- bike
统计 月份的销售总额:
[root@desktop18 Desktop]# gawk '{
>split($,DATE,"-");
> if(DATE[] == ){
> count+=$
> }
>}
>END{
> print "May : "count
>}' database
May :

整数 int 函数

• int 函数去掉小数点后面的数字,仅仅留下整数部分
• 它不会做四舍五入操作
[root@desktop18 Desktop]# gawk 'END {print 31/3}' database
10.3333
[root@desktop18 Desktop]# gawk 'END {printint(31/3)}' database
10

生成随机数

• rand 函数生成一个大于或等于 0,小于 1 的浮点数
• 当多次执行上面的脚本,每次都生成相同的数字
• srand 函数,以当前时刻为 rand()生成一个种子
• srand(x)把 x 设置为种子,通常,程序应该在运行过程中不断的改变 x 的值
当没有种子时,生成的随机数不同文件相同行的随机数是一样的,文件有多少行就生成多少个随机数
[root@desktop18 Desktop]# gawk '{print NR,rand()}' database
0.237788
0.291066
0.845814
0.152208
[root@desktop18 Desktop]# gawk '{print NR,rand()}' /etc/passwd
0.237788
0.291066
0.845814
0.152208
…… ……
0.377663
0.899756
当有种子时,生成的随机数不同文件或同一文件相同行的随机数是不一样的,文件有多少行
就生成多少个随机数
[root@desktop18 Desktop]# gawk 'BEGIN{srand()}{print NR,rand()}' database
0.78965
0.970641
0.284081
0.819256
[root@desktop18 Desktop]# gawk 'BEGIN{srand()}{print NR,rand()}' database
0.532605
0.737259
0.105589
0.0879184

技能掌握测试题:

•1  分析下面数据中,打印出每个销售员 5 月销售的总额
vi sales
Tom 2010-04-09 car 6 6000
Mary 2010-05-07 car 1 1000
Tom 2010-05-20 bike 15 1500
Mary 2010-05-22 car 2 2000
Tom 2010-06-17 car 1 1000
 
•2  以下的数据需要转成 SQL 语句,方便插入到数据库中,注意年月日的格式
vi sales
Tom 04/09/2010 car 6 6000
Mary 05/07/2010 car 1 1000
Tom 05/20/2010 bike 15 1500
Mary 05/22/2010 car 2 2000
SQL 格式
insert into sales value('Tom',2010-04-09,'car',6,6000)
 
题1:
[root@desktop215 Desktop]# gawk '{
> split($,DATE,"-"); 先将日期的月份拆分成一个数组
> if(DATE[] == ){
> name[$]+=$}
> }
# 如果月份是 月,就将以姓名(字符串)为数组下标,将相同名字的销售额相
> END{
> for(Name in name){
> print Name,": 05",name[Name]}
> }' sales
Tom :
Mary :
方法 :
[root@desktop215 Desktop]# gawk '
$ ~ //{name[$]+=$}
END{
for(Name in name){
print Name,": 05",name[Name]}
}' sales
Tom :
Mary :

题二:

[root@desktop215 Desktop]# gawk '{OFS="\t"; print $1,
substr($,,)"-"substr($,,)"-"substr($,,),
$,$,$}' sales2 > /root/Desktop/sales3
[root@desktop215 Desktop]# cat /root/Desktop/sales3
Tom -- car
Mary -- car
Tom -- bike
Mary -- car 导入数据库: mysql> use bluefox;
Database changed mysql> create table sale( name varchar(), time date, spes varchar(), num
int(), money int() );
Query OK, rows affected (0.11 sec)
mysql> select * from sale;
+------+------------+------+------+-------+
| name | time | spes | num | money |
+------+------------+------+------+-------+
| Tom | -- | car | | |
| Mary | -- | car | | |
| Tom | -- | bike | | |
| Mary | -- | car | | |
+------+------------+------+------+-------+
rows in set (0.00 sec)

awk 实用案例介绍的更多相关文章

  1. SQL Delta实用案例介绍,很好的东西,帮了我不少忙

    SQL Delta实用案例介绍 概述 本篇文章主要介绍SQL DELTA的简单使用.为了能够更加明了的说明其功能,本文将通过实际项目中的案例加以介绍. 主要容 Ÿ   SQL DELTA 简介 Ÿ   ...

  2. SQL Delta实用案例介绍

    概述 本篇文章主要介绍SQL DELTA的简单使用.为了能够更加明了的说明其功能,本文将通过实际项目中的案例加以介绍. 主要容 Ÿ   SQL DELTA 简介 Ÿ   创建SQL DELTA项目 Ÿ ...

  3. SQL Delta实用案例介绍 (对应软件)

    http://blog.csdn.net/hongdi/article/details/5363209

  4. JAVA实用案例之水印开发

    写在最前面 上周零零碎碎花了一周的时间研究水印的开发,现在终于写了个入门级的Demo,做下笔记同时分享出来供大家参考. Demo是在我上次写的 JAVA实用案例之文件导入导出(POI方式) 框架基础上 ...

  5. JAVA实用案例之图片水印开发

    写在最前面 上周零零碎碎花了一周的时间研究水印的开发,现在终于写了个入门级的Demo,做下笔记同时分享出来供大家参考. Demo是在我上次写的 JAVA实用案例之文件导入导出(POI方式) 框架基础上 ...

  6. JAVA实用案例之文件导出(JasperReport踩坑实录)

    写在最前面 想想来新公司也快五个月了,恍惚一瞬间. 翻了翻博客,因为太忙,也有将近五个多月没认真总结过了. 正好趁着今天老婆出门团建的机会,记录下最近这段时间遇到的大坑-JasperReport. 六 ...

  7. InfluxDB 聚合函数实用案例

    InfluxDB 聚合函数实用案例 文章大纲 InfluxDB 简介 InfluxDB是GO语言编写的分布式时间序列化数据库,非常适合对数据(跟随时间变化而变化的数据)的跟踪.监控和分析.在我们的项目 ...

  8. 精选19款华丽的HTML5动画和实用案例

    下面是本人收集的19款超酷HTML5动画和实用案例,觉得不错,分享给大家. 1.HTML5 Canvas火焰喷射动画效果 还记得以前分享过的一款HTML5烟花动画HTML5 Canvas烟花特效,今天 ...

  9. 3星|《AI极简经济学》:AI的预测、决策、战略等方面的应用案例介绍

    AI极简经济学 主要内容是AI的各种应用案例介绍.作者把这些案例分到五个部分介绍:预测.决策.工具.战略.社会. 看书名和介绍以为会从经济学的角度解读AI,有更多的新鲜的视角和观点,读后比较失望,基本 ...

随机推荐

  1. Python3程序设计指南:02 数据类型

    目录 1.标识符与关键字 1.1 规则 1.2 约定 2.Integral类型 2.1 整数 2.1.1 数值型操作符与函数 2.1.2 使用数据类型创建对象 2.1.3 整数位逻辑操作符 2.2 布 ...

  2. C语言打印当前所在函数名、文件名、行号

    printf("[%s %s] %s: %s: %d\n", \ __DATE__, __TIME__, __FILE__, __func__, __LINE__); 内核驱动中: ...

  3. linux服务器搭建--将win10换成linux

    在这里说记录一下自己装linux的步骤,如果也有需要的朋友可以参看下: 1.目前win10的系统装成inux系统有3个解决办法: 第一:win10装linux子系统,网上已经有很多教程,步骤很简单 第 ...

  4. POJ 1753 Flip Game(状态压缩+BFS)

    题目网址:http://poj.org/problem?id=1753 题目: Flip Game Description Flip game is played on a rectangular 4 ...

  5. canvas模拟中国铁路运行图

    原理说明 1.在知道canvas画布尺寸的情况下,需要将地理经纬度信息转换为canvas画布x,y坐标,因为中国地图地理经纬度坐标取值范围为73.33-135.05(经度)37-50(维度),所以第一 ...

  6. redis入门(一)

    目录 redis入门(一) 前言 特性 速度快 简单稳定 丰富的功能 历史 历史版本 安装与启动 安装 数据类型与内部编码 数据结构 内部编码 常用API与使用场景 常用命令 字符串 列表 哈希 集合 ...

  7. vue 组件样式如何不影响全局

    可以在 "style" 标签中添加 "scoped" 属性. <style scoped> .red { color: #f00; } </s ...

  8. PHPStorm 10 配置PHPUnit

    PHPStorm 10 配置PHPUnit PHPUnit的安装 自己用的是Xampp,PHPUnit好像自带不好用. 不说废话: 自己看 According to official site htt ...

  9. JVM概述和类加载器

    JVM概述 1.Java虚拟机所管理的内存包括以下几个运行时数据区域:   ①.程序计数器     程序计数器是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器,字节码解释器工作时就是 ...

  10. Handler的postDelayed(Runnable, long)

    handler.postDelayed(myRunnable,1000)是为了轮播图片,每隔1000ms后执行一次run方法,实现轮播实例如下: public void MesageColse(){ ...