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. 记录JS如何使用广度遍历找到节点的所有父节点

    我们在实际的工作业务场景中经常遇到这样的场景,求取树数据中某个节点的父亲节点以及所有的父亲节点,这样的场景下不建议使用深度遍历,使用广度遍历可以更快找到. 1.案例解说 比如树的长相是这样的: 树的数 ...

  2. 网络编程之winInet

    InternetGetConnectedState() 简介: 功能:检索本地系统的网络连接状态. 函数原型:BOOLAPI InternetGetConnectedState(            ...

  3. 宝塔面板6.x版本前台存储XSS+后台CSRF组合拳Getshell

    对于宝塔漏洞复现和练习 0×00  什么是宝塔面板 宝塔面板是一款使用方便,功能强大且终身免费的服务器管理软件,支持Linux 与Windows 系统.一键配置:LAMP / LNMP ,网站,数据库 ...

  4. 转 NAT技术详解

    NAT产生背景 今天,无数快乐的互联网用户在尽情享受Internet带来的乐趣.他们浏览新闻,搜索资料,下载软件,广交新朋,分享信息,甚至于足不出户获取一切日用所需.企业利用互联网发布信息,传递资料和 ...

  5. Async,Await和ConfigureAwait的关系

    [转自]https://mp.weixin.qq.com/s/h10V-FshGoaQUWFPfy-azg 在.NET Framework 4.5中,async / await关键字已添加到该版本中, ...

  6. 压敏电阻的保护作用—NDF达孚电子科技

    压敏电阻是常见的电子元器件之一,它的保护作用被大家熟知和运用.压敏电阻的主要用于在电路承受过压时进行电压钳位,吸收多余的电流以保护灵敏器件.压敏电阻的导电特性随着施加电压的变化呈非线性变化,它能保护电 ...

  7. 百万年薪python之路 -- 面向对象之 反射,双下方法

    面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...

  8. Spring Boot 开发微信公众号后台

    Hello 各位小伙伴,松哥今天要和大家聊一个有意思的话题,就是使用 Spring Boot 开发微信公众号后台. 很多小伙伴可能注意到松哥的个人网站(http://www.javaboy.org)前 ...

  9. GStreamer基础教程11 - 与QT集成

    摘要 通常我们的播放引擎需要和GUI进行集成,在使用GStreamer时,GStreamre会负责媒体的播放及控制,GUI会负责处理用户的交互操作以及创建显示的窗口.本例中我们将结合QT介绍如何指定G ...

  10. mybatis的插件机制

    一.mybatis的插件介绍 关于mybatis的插件,我想大家也都用过,就比如最常用的逆向工程,根据表结构生成model,dao,xml文件,还有分页插件,那这些插件的工作原理是怎么样的呢,就比如分 ...