awk 简介

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

从文件输入

• 格式:
–gawk '/匹配字符串/' 文件名
–gawk '{处理动作}' 文件名
–gawk '/匹配字符串/ {处理动作}' 文件名
实例:
  1. [root@desktop243 Desktop]# gawk -F: '/student/{print $3}' /etc/passwd
  2.  
  3. #-F:以":"号为分隔符分割出参数
  4. [root@desktop243 Desktop]# gawk -F: '/student/{print $1,$3}' /etc/passwd
  5. student
  6. [root@desktop243 Desktop]# gawk -F: '/student/{print $0}' /etc/passwd
  7. student:x::::/home/student:/bin/bash

awk 工作原理

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

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

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

从命令输入

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

格式化输出 print 函数

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

OFMT 变量

在 OFMT 中定义数字的格式
  1. 模拟分区大小的转换,保留小数点后 位:
  2. [root@desktop243Desktop]#echo -e "/dev/sda1\t1234325\n/dev/sda3\t2209"\
  3. > | gawk '{OFMT="%.2f";print $1":",$2/1024,"M"}'
  4. /dev/sda1: 1205.40 M
  5. /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 雷同
–转义字符
  1. [root@desktop243 Desktop]# cat names
  2. Tome Savage
  3. Molly Lee
  4. John Doe
  5. names 文件中第 列的第一个字符:-%c 字符
  6. [root@desktop243 Desktop]# gawk '{printf("The charcter is %c\n",$2)}' names
  7. The charcter is S
  8. The charcter is L
  9. The charcter is D
  10. names 文件中第 列的字符串:–%s 字符串
  11. [root@desktop243 Desktop]# gawk '{printf("The string is %s\n",$2)}' names
  12. The string is Savage
  13. The string is Lee
  14. The string is Doe
  15. 打印一个人的名字和年龄:–%d 十进制整数
  16. 规定好了是字符串或者整数,后面的变量就必须是与之匹配的类型,否则会出错。
  17. [root@desktop243 Desktop]# echo "yangwawa 10"|gawk \
  18. > '{printf("%s is %d years old.\n",$1,$2)}'
  19. yangwawa is years old.
–%f 浮点数
  1. [root@desktop243 Desktop]# echo "yangwawa 10 155"|gawk\
  2. > '{printf("%s is %d years old,his heigth si %.2fm.\n",$1,$2,$3/100)}'
  3. yangwawa is years old,his heigth si 1.55m.

printf 函数修饰符

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

文件中的 awk 命令

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

记录与字段

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

字段分隔符

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

模式

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

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

操作

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

正则表达式

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

匹配操作符

• 前面介绍了模式,也可以对特定的列使用模式匹配符"~",与条件做比较
• 语法:
• ~//
或者
!~ / /
  1. [root@desktop2 Desktop]# gawk -F: '$1 ~ /[sS]tud*/{print $1":"$3}' /etc/passwd
  2. 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的模式或指令要处理,将它们都写在脚本中
• #为注释符
• 一行多条命令要用分号隔开
• 操作跟在模式之后的话,必须一行书写完(即左大括号在同一行)
  1. [root@desktop2 Desktop]#vim info
  2. #!/bin/gawk
  3. # The first awk script
  4. /student/ { print "Studentid is" , $}
  5. /vistor/ {print "vistor id is", $}
  6. 运行:
  7. [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
}
实例:
  1. [root@desktop2Desktop]#echo "111 333"| gawk '{max=$1>$2?$1:$2;print max}'
  2.  
  3. [root@desktop Desktop]# cat /etc/passwd | gawk -F: '{printf("%s is %s
  4. user\n",$1,$3 >= 500?"Normal":"System") }'
  5. rootis System user
  6. bin is System user
  7. …… ……
  8. student is Normal user
  9. 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数据表中的缺空数据
  1. [root@shiyan ~]# cat employees
  2. Name Numbers Time Price
  3. Tome //
  4. Marry //
  5. Molly //
  6. John //
  7. Tome //
  8. Molly //
  9. John //
  10. [root@shiyan ~]# gawk 'NF !=4 {print NR,": has only",NF,"fileds"}' employees
  11. : has only fileds
  12. : 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
• 格式
–变量 = 表达式
  1. [root@sya ~]#gawk'$1~/^T/{wage=$2*$4;print$1,$3,"wage:",wage}' ./employees
  2. Tome // wage:
  3. Tome // wage:

BEGIN 模式

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

END 模式

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

输出重定向

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

输入重定向-读输入 getline

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

Bash 向 awk 发送参数

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

管道

打开管道的前提是其他管道必须关闭,每次只能打开一个管道,这和 Linux 中一条命令无
限次的使用管道不同
• 管道右边的命令必须写在双引号之间
  1. [root@shiyan ~]# gawk '/^[^#:]+/{print $1}' /etc/hosts
  2. 127.0.0.1
  3. 172.24.205.191
  4. 172.24.200.254
  5. 172.24.254.254
  6. [root@shiyan ~]# gawk '/^[^#:]+/{print $1 |"ping -c2 "$1}' /etc/hosts
  7. PING 127.0.0.1 (127.0.0.1) () bytes of data.
  8. bytes from 127.0.0.1: icmp_seq= ttl= time=0.028 ms
  9. connect: Network is unreachable
  10. connect: Network is unreachable
  11. connect: Network is unreachable
  12. bytes from 127.0.0.1: icmp_seq= ttl= time=0.037 ms
  13. --- 127.0.0.1 ping statistics ---
  14. packets transmitted, received, % packetloss, time 999ms
  15. 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 命令必须用双引号
  1. [root@desktop1 Desktop]# gawk '/^[^#:]/{ if(system("ping -c2 "
  2. $" > /dev/null")== ){print $" is on line"}else{ print $" is down"}}' /etc/hosts
  3. 127.0.0.1 is on line
  4. 172.24.0.2 is down
  5. 172.24.200.254 is on line
  6. 172.24.254.254 is on line
  7.  
  8. 注意里面的空格“

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;…… # 语句成立一直执行部分
}
  1. [root@desktop Desktop]# gawk -F: '{print NR,":User info:\n======";i=1;
  2. while(i<=NF){print $i;i++};print "\n"}' /etc/passwd
  3. :User info:
  4. ======
  5. root
  6. x
  7.  
  8. root
  9. /root
  10. /bin/bash
  11. …… ……
  12. :User info:
  13. ======
  14. visitor
  15. x
  16.  
  17. /home/visitor
  18. /bin/bash

for 循环

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

循环控制

break 用来终止循环
• continue 语句 用来不做后续操作,绕过此次循环,继续下一循环
实例:
  1. 为了方便实验,创建一个/tmp/passwd:
  2. [root@localhost ~]# cat /tmp/passwd
  3. avahi-autoipd:x:::avahi-autoipd:/var/lib/avahi-autoipd:/sbin/nologin
  4. student:x::::/home/student:/bin/bash
  5. visitor:x::::/home/visitor:/bin/bash
  6. harry:x::::/home/harry:/bin/bash
  7. [root@desktop Desktop]# gawk -F: '{i=1;
  8. while(i++ < NF ){
  9. if($i~/daemon/)
  10. {print NR,$;break;}
  11. }
  12. }' /etc/passwd
  13. daemon
  14. haldaemon
  15. avahi
  16. continue 语句:会将匹配的这行其他段打印出来,继续往下查询
  17. [root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;
  18. while(i++ < NF){if($i~/student/){ print "========";continue; }
  19. else { print $i ;}}}'
  20. avahi-autoipd
  21. x
  22.  
  23. avahi-autoipd
  24. /var/lib/avahi-autoipd
  25. /sbin/nologin
  26. ========
  27. x
  28.  
  29. ========
  30. /bin/bash
  31. visitor
  32. x
  33.  
  34. /home/visitor
  35. /bin/bash
  36. harry
  37. x
  38.  
  39. /home/harry
  40. /bin/bash
  41. break 语句:匹配的这行其他段都不会打印,继续往下查询
  42. [root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;
  43. while(i++ < NF){if($i~/student/){ print "========";break; }
  44. else { print $i ;}}}'
  45. avahi-autoipd
  46. x
  47.  
  48. avahi-autoipd
  49. /var/lib/avahi-autoipd
  50. /sbin/nologin
  51. ========
  52. visitor
  53. x
  54.  
  55. /home/visitor
  56. /bin/bash
  57. harry
  58. x
  59.  
  60. /home/harry
  61. /bin/bash

next 语句

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

exit 语句

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

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

关联数组的下标

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

用字符串作为数组的下标

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

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

处理命令行参数

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

字符串 sub 和 gsub 函数

sub 和 gsub 函数,可以在条目中查找与给定的正则表达式匹配的字符串,并取代它
• sub 和 gsub 的区别是,前者只对匹配部分一次替换,后者为全部替换
• 语法:
–sub( 正则表达式 , 替换字符串) #默认为$0,整条记录
–sub( 正则表达式,替换字符串 , 目标字段); #指定的字段
换名字:
  1. [root@desk18Desktop]# gawk '{sub(/[Tt]om/,"ttooomm",$1);print $0}' employess
  2. ttooomm //
  3. Mary //
  4. Bill //
  5. Mary //
  6. ttooomm //
  7. sub:只对匹配部分一次替换
  8. [root@desktop18 Desktop]# gawk '{sub(/0/,"kkkkk");print $0}' employess
  9. Tom 2kkkkk08//
  10. Mary 2kkkkk08//
  11. Bill 2kkkkk09//
  12. Mary 2kkkkk09//
  13. Tom 2kkkkk09//
  14. gsub 全部替换
  15. [root@desktop18 Desktop]# gawk '{gsub(/0/,"kkkkk");print $0}' employess
  16. Tom 2kkkkkkkkkk8/kkkkk3/kkkkk5
  17. Mary 2kkkkkkkkkk8/kkkkk4/kkkkk6
  18. Bill 2kkkkkkkkkk9/1kkkkk/kkkkk9
  19. Mary 2kkkkkkkkkk9/1kkkkk/
  20. 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 #不带参数,返回记录中的字符个数
  1. 带参数:
  2. [root@desktop18 Desktop]# echo "123qwe" | gawk 'BEGIN{getline RR <"-";print
  3. length(RR)}'
  4.  
  5. [root@desktop18 Desktop]# gawk '{print $1,length($1)}' employess
  6. Tom
  7. Mary
  8. Bill
  9. Mary
  10. Tom
  11. 不带参数:
  12. [root@desktop18 Desktop]# gawk '{print $1,length}' employess
  13. Tom
  14. Mary
  15. Bill
  16. Mary
  17. Tom

字符 substr 函数

• substr函数返回从字符串指定位置开始的一个子字符串。
• 如果指定了子字符串的长度,返回字符串的对应的部分
• 语法:
–substr(字符串,起始位置)
–substr(字符串,起始位置,子字符串长度)
  1. [root@desktop18 Desktop]# gawk '{print substr($1,2,length)}' employess
  2. om
  3. ary
ill
  1.  
ary
  1.  
om
  1.  
[root@desktop18 Desktop]# gawk '{print substr($3,1,4)}' employess
  1.  
2008
  1.  
2008
  1.  
2009
  1.  
2009
  1.  
2009
  1.  
将 employess 中的日期换成另一种格式
  1.  
[root@desktop18 Desktop]# gawk '{print $1,$2,
  1.  
substr($3,9,2)"/"substr($3,6,2)"/"substr($3,1,4),$4}' employess
  1.  
Tom 234 05/03/2008 685
  1.  
Mary 451 06/04/2008 932
  1.  
Bill 127 09/10/2009 3456
  1.  
Mary 341 18/10/2009 4532
  1.  
Tom 465 10/11/2009 3421
  1.  

字符 match 函数

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

字符 split 函数

• split 函数用来将一个字符串拆分成一个数组
• 语法:
–split(字符串, 保存数据的数组,字段分隔符)
#注意 Split 函数切割的数组下标从 1 开始,0 永远为空
–split(字符串, 保存数据的数组 ) #使用 FS 默认值
  1. [root@desktop18 Desktop]# cat database
  2. -- car
  3. -- car
  4. -- dog
  5. -- bike
  6. 统计 月份的销售总额:
  7. [root@desktop18 Desktop]# gawk '{
  8. >split($,DATE,"-");
  9. > if(DATE[] == ){
  10. > count+=$
  11. > }
  12. >}
  13. >END{
  14. > print "May : "count
  15. >}' database
  16. 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 的值
当没有种子时,生成的随机数不同文件相同行的随机数是一样的,文件有多少行就生成多少个随机数
  1. [root@desktop18 Desktop]# gawk '{print NR,rand()}' database
  2. 0.237788
  3. 0.291066
  4. 0.845814
  5. 0.152208
  6. [root@desktop18 Desktop]# gawk '{print NR,rand()}' /etc/passwd
  7. 0.237788
  8. 0.291066
  9. 0.845814
  10. 0.152208
  11. …… ……
  12. 0.377663
  13. 0.899756
  14. 当有种子时,生成的随机数不同文件或同一文件相同行的随机数是不一样的,文件有多少行
  15. 就生成多少个随机数
  16. [root@desktop18 Desktop]# gawk 'BEGIN{srand()}{print NR,rand()}' database
  17. 0.78965
  18. 0.970641
  19. 0.284081
  20. 0.819256
  21. [root@desktop18 Desktop]# gawk 'BEGIN{srand()}{print NR,rand()}' database
  22. 0.532605
  23. 0.737259
  24. 0.105589
  25. 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. 1
  2. [root@desktop215 Desktop]# gawk '{
  3. > split($,DATE,"-"); 先将日期的月份拆分成一个数组
  4. > if(DATE[] == ){
  5. > name[$]+=$}
  6. > }
  7. # 如果月份是 月,就将以姓名(字符串)为数组下标,将相同名字的销售额相
  8. > END{
  9. > for(Name in name){
  10. > print Name,": 05",name[Name]}
  11. > }' sales
  12. Tom :
  13. Mary :
  14. 方法
  15. [root@desktop215 Desktop]# gawk '
  16. $ ~ //{name[$]+=$}
  17. END{
  18. for(Name in name){
  19. print Name,": 05",name[Name]}
  20. }' sales
  21. Tom :
  22. Mary :

题二:

  1. [root@desktop215 Desktop]# gawk '{OFS="\t"; print $1,
  2. substr($,,)"-"substr($,,)"-"substr($,,),
  3. $,$,$}' sales2 > /root/Desktop/sales3
  4. [root@desktop215 Desktop]# cat /root/Desktop/sales3
  5. Tom -- car
  6. Mary -- car
  7. Tom -- bike
  8. Mary -- car
  9.  
  10. 导入数据库:
  11.  
  12. mysql> use bluefox;
  13. Database changed
  14.  
  15. mysql> create table sale( name varchar(), time date, spes varchar(), num
  16. int(), money int() );
  17. Query OK, rows affected (0.11 sec)
  18. mysql> select * from sale;
  19. +------+------------+------+------+-------+
  20. | name | time | spes | num | money |
  21. +------+------------+------+------+-------+
  22. | Tom | -- | car | | |
  23. | Mary | -- | car | | |
  24. | Tom | -- | bike | | |
  25. | Mary | -- | car | | |
  26. +------+------------+------+------+-------+
  27. 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. Java并发编程总结(一)Syncronized解析

    Syncronized解析 作用: )确保线程互斥的访问同步代码 )保证共享变量的修改能够及时可见 )有效解决重排序问题. 用法: )修饰普通方法(锁是当前实例对象) )修饰静态方法(锁是当前对象的C ...

  2. python requests简单接口自动化

    get方法 url:显而易见,就是接口的地址url啦 headers:定制请求头(headers),例如:content-type = application/x-www-form-urlencode ...

  3. 一个关于内联优化和调用约定的Bug

    很久没有更新博客了(博客园怎么还不更新后台),前几天在写一个Linux 0.11的实验 [1] 时遇到了一个奇葩的Bug,就在这简单记录一下调试过程吧. 现象 这个实验要求在Linux 0.11中实现 ...

  4. Python的Argparse模块是什么?

            近日在阅读代码的过程中遇到了Argparse模块,记得前段时间已经看了,可是过了两周现在又忘了, 看来写代码一定要钻研到底搞清楚其中原委才行,本文主要参考Python3.6系列官方文档 ...

  5. C# 中yield关键字解析

    前言 前段时间了解到yield关键字,一直觉得还不错.今天给大家分享一下yield关键字的用法.yield return 返回集合不是一次性返回所有集合元素,而是一次调用返回一个元素.具体如何使用yi ...

  6. OTA升级详解(一)

    不积跬步,无以至千里: 不积小流,无以成江海. 出自荀子<劝学篇> 1.概念解释 OTA是何物? 英文解释为 Over The Air,既空中下载的意思,具体指远程无线方式,OTA 技术可 ...

  7. SQLServer执行大脚本文件时,提示“无法执行脚本没有足够的内存继续执行程序 (mscorlib)”

    问题描述: 有时候服务器操作导入数据.sql,或者 当需求不可以直接备份整库还原时,往往通过导出数据库脚本的方式来部署-还原数据库表 但是当数据库导出脚本很大,用Microsoft SQL Serve ...

  8. 数据结构(三十二)图的遍历(DFS、BFS)

    图的遍历和树的遍历类似.图的遍历是指从图中的某个顶点出发,对图中的所有顶点访问且仅访问一次的过程.通常有两种遍历次序方案:深度优先遍历和广度优先遍历. 一.深度优先遍历 深度优先遍历(Depth_Fi ...

  9. python *args,**kwargs参数

    实际上,关键的是*和** 我们以三个例子来解释: 普通的使用参数: def test1(arg): print(arg) test1("a") 输出: a *是将剩下的参数用元祖表 ...

  10. Linux 提示符格式及颜色

    # 提示符颜色配置: 颜色  黑   红  绿  黄  青   紫  蓝  白 字体  30  31  32  33 34  35  36  37 背景  40  41  42  43 44  45 ...