文本处理神器Awk语言详解

文章目录

    • 初步认识
      • 命令执行
      • 脚本文件
      • 输入输出
      • 管道
    • 基本语法
      • 运算符
      • 流程控制
      • 函数封装
    • 内置变量
    • 内置函数
      • 算术和位操作函数
      • 字符串函数与正则表达式
      • 字符输出函数
      • 时间函数
      • 其它函数

初步认识

AWK主要用于文本数据处理,由Afred, Weinberger和Kernighan设计,故名AWK。

AWK的初始版本由AT&T实验室开发,此外,NAWK是AWK的改进版本,而应用最广泛的当属GAWK,即GNU AWK,为Linux内置的默认版本,对AWK和NAWK可以完全兼容。

Awk的程序结构包括三个区块:

  • 开始块BEGIN {awk-commands}
  • 主体块/pattern/ {awk-commands}
  • 结束块END {awk-commands}

其中awk-commands表示awk指令;/pattern/表示指定的处理模式。

以文本文件test.txt为例,下面为其内容

1)    Amit     Physics    80
2)    Rahul    Maths      90
3)    Shyam    Biology    87

命令执行

通过awk可以逐行打印出这个文本文件,并可以添加表头,方法如下

$ awk 'BEGIN{printf "No\tName\tSub\tMarks\n"}{print}' test.txt
No      Name    Sub     Marks
1)    Amit     Physics    80
2)    Rahul    Maths      90
3)    Shyam    Biology    87

其基本方法为,可用awk直接调用后面的字符串中所写的脚本命令。其中BEGIN标识的大括号为开始块,用于打印表头;后面的{print}为主体块,表示按行打印test.txt中的内容。

通过$选列,可实现单行输出,例如只想输出人名,则

awk 'BEGIN{printf "Name\n"}{print $2}' test.txt
Name
Amit
Rahul
Shyam

其中$2表示第二列。

脚本文件

通过awk -f命令,可以执行脚本,例如可将同样的功能封装入脚本test.awk中,

# test.awk文件
BEGIN{
    printf "Name\n"
}
{
    print $2
}

然后在命令行中调用,其效果与刚刚相同

$ awk -f test.awk  test.txt
Name
Amit
Rahul
Shyam

输入输出

除了可以将处理结果打印在命令行中,awk也可以将其输出到文本文件,其方法为

print DATA > oFile
print DATA >> oFile

可将DATA输出到oFile中,如果oFile不存在,则先创建该文件。>为写入模式,若oFile存在,数据输出前会将oFile中原有的数据删除;>>为追加模式,数据将在oFile结尾写入。

下例将test.txt打开,并重新存储到new.txt

awk '{ print $0 > "./new.txt" }' test.txt

当然也可以交换两列的位置

$ awk '{print $4,$3,$2,$1 > "./new.txt"}' test.txt
$ cat new.txt
80 Physics Amit 1)
90 Maths Rahul 2)
87 Biology Shyam 3)

管道

AWK可通过管道将一个程序的输出传递给另一个程序,其使用方法为

print items | command

例如下例将hello, world"传递给tr

$ awk 'BEGIN { print "hello, world" | "tr [a-z] [A-Z]" }'
HELLO, WORLD !!!

通过|&可使用双工管道,进行双向通信

# 文件pipe.awk
BEGIN {
    cmd = "tr [a-z] [A-Z]"  # 建立双向通信惯导
    print "hello, world !!!" |& cmd # 为tr提供输入
    close(cmd, "to")        # 执行后关闭to进程
    cmd |& getline out      # 将输出存储到out中
    print out;              # 打印out
    close(cmd);             # 关闭cmd
}

执行脚本后可得到

HELLO, WORLD !!!

基本语法

运算符

+, -, *, \, %, ^, ** 加减乘除、取模、乘方、乘方
+=, -=, *=, \=, %=, ^= 加减乘除、取模、乘方对应的复制符
++a, --a, a++, a-- 前置递增、前置递减、后置递增、后置递减
==, !=, <, <=, >, >= 关系运算符,返回真假
`&&,

awk也支持三元运算符,例如

$ awk 'BEGIN { a = 10; b = 20; (a > b) ? max = a : max = b; print "Max =", max}'
Max = 20

除了单个值的计算,awk还提供了适用于其他数据类型的运算符

  • 字符串连接:空格
  • 数组遍历:in
  • 匹配:~;不匹配!~

数组遍历的方法为:

BEGIN {
    arr[0] = 1; 
    arr[1] = 2; 
    arr[2] = 3; 
    for (i in arr) 
        printf "arr[%d] = %d\t", i, arr[i] 
    print "\n"
}

调用结果为:

awk -f test.awk
arr[0] = 1      arr[1] = 2      arr[2] = 3

流程控制

编程语言的流程控制,主要包括判断和循环。

其判断语句就是if...else if...else的结构:

$ awk 'BEGIN{num=10; if(num%2==0){printf "%d is even\n", num }else{printf "%d is odd"}}'
10 is even

循环在前面的例子也出现过,包括for循环、while循环以及do{}while(),其逻辑与C语言极度相似,故只列一例不做详述。

$ awk 'BEGIN { for (i = 1; i <= 5; ++i) printf "%d\t",i }'
1       2       3       4       5
$ awk 'BEGIN{ i=1; while(i<5){printf "%d\t", i; i++}}'
1       2       3       4
$ awk 'BEGIN{ i=1; do{printf "%d\t", i++}while(i<5)}'
1       2       3       4

在循环中可以通过breakcontinue来结束或跳过本层循环,这也同样与C语言雷同。此外,awk还有一个关键字exit,类似于return 0,可以跳出当前程序。

函数封装

awk中封装函数用关键字function,例如

# 文件 fcunTest.awk
function fac(n){
    if(n>1)
        return n*fac(n-1)
    else
        return 1
}
BEGIN{
    printf "5+1=%d", fac(5)
}

这是个递归求阶乘的函数,调用结果为

$ awk -f funcTest.awk
fac(5)= 120

内置变量

AWK 提供了一些内置变量,列表如下

变量 说明 默认值
ARGC 表示在命令行提供的参数的个数
ARGV 命令行输入的参数数组 索引从0开始
CONVFMT 数据转换为字符串的格式 %.6g
OFMT 数值输出格式 %.6g
ENVIRON 环境变量数组
FILENAME* 当前文件名称
FS 输入列之间的分隔符 空格
NF 当前输入记录中域的数量
NR 当前记录的数量
FNR 当前文件的NR
OFS 输出列之间的分割符 空格
ORS 行间分割符 换行符
RLENGTH match匹配字符串长度
RS 输入行的分割符 换行符
RSTART match匹配字符串的首字符的位置
SUBSEP 数组下标的分割行符 \03
$0 整个输入记录
$n 当前输入的第n列

* 表示开始块中未定义

ARGVARGC为例,可演示一下如何查看这些默认变量

awk 'BEGIN { for (i = 0; i < ARGC - 1; ++i)
    { printf "ARGV[%d] = %s\t", i, ARGV[i] } 
    }' a b c d
ARGV[0] = awk ARGV[1] = a   ARGV[2] = b  ARGV[3] = c

此外,GNU AWK还提供了其他几个内置变量

ARGIND 正在处理的ARGV索引
ERRNO 失败信息
FIELDWIDTHS 列宽
IGNORECASE 设置后大小写不敏感
TEXTDOMAIN AWK程序当前文本域
  • BINMODE:即二进制模式,用于非 POSIX 系统。 数值1、2、3分别指定输入文件、输出文件或所有文件;字符串rw分别指定输入或输出文件使用二进制模式;rwwr指定所有文件使用二进制模式。

  • LINT:提供了在GAWK程序中动态控制--lint选项的一种途径。此变量设置后,GAWK会输出lint警告信息。如果给此变量赋予字符值fatal,lint 的所有警告信息将会变了致命错误信息(fatal errors)输出,和–lint=fatal 效果一样。

内置函数

算术和位操作函数

and, or, compl, xor 按位求与、或、非、异或
lshift, rshift 左移位、右移位
cos(x), sin(x) cos ⁡ x , sin ⁡ x \cos x, \sin x cosx,sinx
exp(x), log(x), sqrt(x) exp ⁡ x , ln ⁡ x , x \exp x, \ln x, \sqrt x expx,lnx,x
atan2(y,x) arctan ⁡ y x \arctan\frac{y}{x} arctanxy
int(x) 取整
rand(), srand(n) 返回区间 ( 0 , 1 ) (0,1) (0,1)的一个随机数
后者根据随机数种子n来生成

字符串函数与正则表达式

基础功能
asort(arr,[, d [,how] ]) 对数组arr的值进行字符排序
asorti(arr,[, d [,how] ]) 对数组arr的索引进行字符排序
gsub(a, b [, tar]) tar中的子串a替换为btar默认$0
index(str,sub) 返回substr的位置;若不存在则返回0
length(str) 返回字符串长度
strtonum(str) str转为数值 [ 1 ] ^{[1]} [1]
tolower(str) str转换为小写格式然后返回 [ 1 ] ^{[1]} [1]
toupper(str) str转换为大写格式然后返回 [ 1 ] ^{[1]} [1]
substr(str, st, L) 返回str中从第st个字符开始长度为L的子串
  • [1] strtonum的输入字符串,如以0开始,则转为八进制数;如以0x0X开始,则当作十六进制数;否则当作浮点数。
  • [2] tolowertoupper并不会改变输入字符串str本身。
与正则表达式相关的功能
match(str, regex) 返回在str中与regex匹配的子串的位。
sub(regex,sub,str) str首次出现的与regex匹配的子串替换为sub
str默认为$0
split(str, arr,regex) 使用regex分割str,输出给arr

其中regex均表示正则表达式;match返回的字符串为匹配的最长、最左侧的字符串,如果匹配失败,返回0。

所谓正则表达式,就是通过匹配符来替代特定文字的方法,其常用的匹配字符如下

匹配字符
. 除了行结束字符的所有字符
^ 匹配一行的开始
$ 匹配一行的结束
[] 匹配方括号中的任意字符
[^] 匹配除了[^]中间的其他字符
? 其前面的字符不出现或出现一次
其前面的字符不出现或出现多次
+ 其前面的字符出现一次或多次

字符输出函数

sprintf(format,expr-list) 按指定格式(format)将参数列表 expr-list 构造成字符串然后返回。

时间函数

systime 返回从 Epoch 以来到当前时间的秒数(在POSIX系统上,Epoch 为1970-01-01 00:00:00 UTC)。

mktime(dataspec) 将字符串dataspec转换为与systime 风格的时间戳,dataspec字符串的格式为 YYYY MM DD HH MM SS。

strftime([format [, timestamp[, utc-flag]]]) 根据 format 指定的格式将时间戳 timestamp 格式化。

日期格式说明如下:

SN 描述 SN 描述
%a 星期缩写 %A 星期全称
%b 月份缩写 %B 月份全称
%c 本地日期与时间 %C 世纪数
%d 十进制日期(01-31) %D 等价于 %m/%d/%y.
%e 日期,如果只有一位数字则用空格补齐
%F 等价于 %Y-%m-%d
%G 标准周所在年份的全称 %g 标准周所在的年份模除100
%h 等价于 %b
%H 24小时格式的小时[00-23] %I 12小时格式的小时[00-12]
%j 一年中的第几天[001-366]
%m 月份[01-12] %M 分钟数[00-59]
%n 换行符 (ASCII LF)
%p 十二进制表示法(AM/PM)
%r 等价于 %I:%M:%S %p %R 等价于 %H:%M。
%S 时间的秒数值(00-60)
%t 制表符 (tab) %T 等价于 %H:%M:%S。
%u 以数字表示的星期(1-7),1 表示星期一。
%U 一年中星期序号 %V 一年中星期序号
%w 星期[0-6],0表示星期日 %W 一年中星期序号s
%x 本地日期表示 %X 本地时间表示
%y 年份模除100 %Y 十进制表示的完整年份。
%z 时区,表示格式为+HHMM
%Z 时区名称或缩写,如果时区待定则无输出。

其中,%U以周日为一周开始;%V, %W以周一作为一周开始;

%z的表示格式为+HHMM(例如,格式要求生成的 RFC 822或者 RFC 1036 时间头)

其它函数

close(expr) 关闭管道的文件
delete 从数组中删除元素
exit 终止脚本执行
flush 刷新打开文件或管道的缓冲区
getline 读入下一行
next 停止处理当前记录,并且进入到下一条记录的处理过程
nextfile 停止处理当前文件,从下一个文件第一个记录开始处理。
system 执行特定的命令,返回其退出状态,0表示成功,否则表示失败

你可能感兴趣的:(编程语言学习,python,linux,开发语言)