Shell 学习—AWK介绍

Shell 学习—AWK

= = = 安装awk

root@kiki-desktop:~/shell# apt-get install gawk gawk-doc

= = = awk 是一种程序语言. 它具有一般程序语言常见的功能.

= = =.因awk语言具有某些特点,

如 : 使用直译器(Interpreter)不需先行编译;

 变量无类型之分(Typeless), 可使用文字当数组的下标(Associative Array)...等特色. 因此, 使用awk撰写程序比起使用其它语言更简洁便利且节省时间.

 awk还具有一些内建功能, 使得awk擅于处理具数据行(Record), 字段(Field)型态的资料;

 此外, awk内建有pipe的功能, 可将处理中的数据传送给外部的 Shell命令加以处理, 再将Shell命令处理后的数据传回awk程序, 这个特点也使得awk程序很容易使用系统资源.

= = =  awk程序的主要结构:

awk程序中主要语法是 Pattern { Actions}, 故常见之awk 程序其型态如下 :

Pattern1 { Actions1 }

= = =  Actions 是什么?

Actions 是由许多awk指令构成. 而awk的指令与 C 语言中的指令十分类似.

例如 :

awk的 I/O指令 : print, printf( ), getline...

awk的 流程控制指令 : if(...){..} else{..}, while(...){...}...

= = =  例子

有时语法 Pattern { Actions }中, Pattern 部分被省略,只剩 {Actions}.这种情形表示 "无条件执行这个 Actions".

50 > 23 {print "Hello! The word!!" }

"banana" ~ /123/ { print "Good morning !" }

# awk '{print $2,$3*$4}' emp

UNIX命令行上, 执行awk的语法为:

$awk 'awk程序' 欲处理的资料文件文件名

# cat file1 | awk -F , {'print $1,$2'}

 

= = =  例如 : awk 从资料文件 emp.dat 中读入第一笔数据行

"A125 Jenny 100 210" 之后, 程序中:

$0 之值将是 "A125 Jenny 100 210"

$1 之值为 "A125"

$2 之值为 "Jenny"

$3 之值为 100

$4 之值为 210

$NF 之值为 4

$NR 之值为 1

$FILENAME 之值为 "emp.dat"

= = =  awk的工作流程 :

执行awk时, 它会反复进行下列四步骤.

自动从指定的数据文件中读取一个数据行.

自动更新(Update)相关的内建变量之值. 如 : NF, NR, $0...

依次执行程序中 所有 的 Pattern { Actions } 指令.

当执行完程序中所有 Pattern { Actions } 时, 若数据文件中还有未读取的数据, 则反复执行步骤1到步骤4.

awk会自动重复进行上述4个步骤, 使用者不须于程序中编写这个循环 (Loop).

= = =  linux中 文本以空格分隔的行就可以默认操作

                            以其他分隔如, ;等等,就可以用awk –f 操作

dengfang,0Rgbo2Kyn0hms

huyibao,0R1d4zCYO3qxk

dengfeng,0RUsQ9pz6kBPs

gongfangping,0Ru/KhW.8Ove6

liucaigeng,0Rekdi5B0sWfU

 

= = =  print 的参数间彼此以 "," (逗号) 隔开, 印出数据时彼此间会以空白隔开.

 

例一,选择符合指定条件的记录

组装部门员工调薪5%,(组装部门员工之ID以"A"开头)

所有员工最后之薪资率若仍低于100, 则以100计.

编写awk程序打印新的员工薪资率报表.

 

原文件:

A125 Jenny 100 210

A341 Dan 110 215

P158 Max 130 209

P148 John 125 220

A123 Linda 95 210

 

[root@kiki-desktop:~/shell# cat adjust1.awk

$1 ~ /^A.*/ {$3*=1.05} $3<100 {$3=100}

{printf("%s %8s %d\n",$1,$2,$3)}

 

root@kiki-desktop:~/shell# cat emp

A125 Jenny 100 210

 

A341 Dan 110 215

 

P158 Max 130 209

 

P148 John 125 220

 

A123 Linda 95 210

 

root@kiki-desktop:~/shell# awk -f  adjust1.awk  emp

A125    Jenny 105

          100

A341      Dan 115

          100

P158      Max 130

          100

P148     John 125

          100

A123    Linda 100

 

例二,统计各科修课人数,并印出结果

 

此为一学生注册的资料文件; 第一栏为学生姓名, 其后为该生所修课程.

Mary O.S. Arch. Discrete

Steve D.S. Algorithm Arch.

Wang Discrete Graphics O.S.

Lisa Graphics A.I.

Lily Discrete Algorithm

.

建立如下程序,并取名为 course.awk:

{ for( i=2; i <= NF; i++) Number[$i]++ }

END{for(course in Number) printf("%10s %d\n", course, Number[course] )}

执行下列命令 :

$awk -f course.awk reg.dat

执行结果如下 :

  Graphics 2

      O.S. 2

  Discrete 3

      A.I. 1

      D.S. 1

     Arch. 2

 Algorithm 2

解说:指令中END 为awk之保留字, 为 Pattern 的一种.

END 成立(其值为true)的条件是: "awk处理完所有数据, 即将离开程序时. "

平常读入数据行时, END并不成立, 故其后的Actions 并不被执行;

唯有当awk读完所有数据时, 该Actions才会被执行 ( 注意, 不管数据行有多少笔, END仅在最后才成立, 故该Actions仅被执行一次.)

BEGIN 与 END 有点类似, 是awk中另一个保留的Pattern.

唯一不同的是: "以 BEGIN 为 Pattern 的 Actions 于程序一开始执行时, 被执行一次."

 

= = = awk中数组的特性

使用字符串当数组的下标(index).

使用数组前不须宣告数组名及其大小.

例如: 希望用数组来记录 reg.dat 中各门课程的修课人数.

这情况,有二项信息必须储存:

(a) 课程名称, 如: "O.S.","Arch.".. ,共有哪些课程事先并不明确.

(b)各课程的修课人数. 如: 有几个人修"O.S."

在awk中只要用一个数组就可同时记录上列信息. 其方法如下:

使用一个数组 Number[ ] :

以课程名称当 Number[ ] 的下标.

以 Number[ ] 中不同下标所对映的元素代表修课人数.

例如:

有2个学生修 "O.S.", 则以 Number["O.S."] = 2 表之.

若修"O.S."的人数增加一人,则 Number["O.S."] = Number["O.S."] + 1 或 Number["O.S."]++ .

 

例三,写一个awk程序来打印出线上人数.

将下列程序建文件, 命名为 count.awk

BEGIN {

while ( "who" | getline ) n++

print n

}

并执行下列命令 :

awk -f count.awk

执行结果将会印出目前在线人数

getline var

pipe 变量

变量 var(var省略时,表示置于$0)

 

例四,重定向输出到文件

 

root@kiki-desktop:~/shell# cat arr.dat

1034 7:26

 

1025 7:27

 

1101 7:32

 

1006 7:45

 

1012 7:46

 

1028 7:49

 

1051 7:51

 

1029 7:57

 

1042 7:59

 

1008 8:01

 

1052 8:05

 

1005 8:12

root@kiki-desktop:~/shell# cat reformat1.awk

BEGIN { print " ID Number Arrival Time" > "today_rpt1"

 

print "===========================" > "today_rpt1"

 

}

 

{ printf(" %s %s\n", $1,$2 ) > "today_rpt1" }

root@kiki-desktop:~/shell#

root@kiki-desktop:~/shell#

root@kiki-desktop:~/shell# awk -f reformat1.awk arr.dat

root@kiki-desktop:~/shell#

 

= = = awk 中如何利用系统资源

注 : awk input 指令只有 getline 一个.

awk output 指令有 print, printf() 二个.

在a 语法中, awk所输出的数据将转送往 Shell , 由 Shell 的命令进行处理.以上例而言, print 所输出的数据将经由 Shell 命令 "sort -k 1" 排序后再送往屏幕(stdout).

上列awk程序中, "print$1, $2" 可能反复执行很多次, 其输出的结果将先暂存于 pipe 中,等到该程序结束时, 才会一并进行 "sort -k 1".

须注意二点 : 不论 print $1, $2 被执行几次, "sort -k 1" 的执行时间是 "awk程序结束时",

[a. 语法] awk output 指令 | "Shell 接受的命令"

( 如 : print $1,$2 | "sort -k 1" )

 

例5,

root@kiki-desktop:~/shell# awk '

> BEGIN{

> system("date > date.dat")

> getline < "date.dat"

> print "Today is ", $2, $3

> }

> '

Today is  Jan 26

 

= = = = 执行 awk 程序的几种方式= = = =

若欲执行该awk程序, 来印出文件 today_rpt1 及 today_rpt2 的内容时,

必须于 UNIX 的命令行上执行下列命令 :

方式一 awk -f mydump.awk today_rpt1 today_rpt2

方式二 awk '{print}' today_rpt1 today_rpt2第二种方式系将awk 程序直接写在 Shell 的命令行上, 这种方式仅适合较短的awk程序.

方式三 建立如下之 shell script, 并取名为 mydisplay, $ ./mydisplay today_rpt1 today_rpt2

 

#!/bin/sh

# 注意以下的 awk 与 ' 之间须有空白隔开

awk '

{print}

' $*

# 注意以上的 ' 与 $* 之间须有空白隔开

 

例5,$ ./mydisplay  #(未接任何数据文件文件名)

将会发现: 此后键入的任何数据将逐行复印一份于屏幕上. 这情况不是机器当机 ! 是因为awk程序正处于执行中. 它正按程序指示, 将读取数据并重新dump一次; 只因执行时未指定数据文件文件名, 故awk 便以stdin(键盘上的输入)为数据来源. 读者可利用这个特点, 设计可与awk即时聊天的程序.

 

root@kiki-desktop:~/shell# ./mydisplay

kiki

kiki

 

 

kiki

kiki

 

 

mina

mina

 

例6,改变 awk 切割字段的方式 & 自定义函数

 

范例 : ] 承接 6.2 的例子, 若八点为上班时间, 请加注 "*"于迟到记录之前, 并计算平均上班时间.

posted on 2014-04-12 23:09  mybloges  阅读(339)  评论(0编辑  收藏  举报

导航