Linux之GAS: awk小记

2018-04-30  本文已影响18人  齐州读经客

1 说明

man awk:
awk - pattern scanning and processing language

awk的名字来源于三位创始人的姓氏:Alfred Aho,Peter Weinberger, 和 Brian Kernighan。类似sed,awk每次读取一行为进行处理,但处理的最小单位是字段(也就是列,通常使用空格或制表符分隔),因此适合处理表格一类的数据。但同时awk不止是一个程序/命令,还是一门程序设计(脚本式的)语言,常应用于各种计算和数据处理任务。

参考资料

2 基本

awk命令的基本形式:

awk [options] SCRIPT [file]

SCRIPT结构:
脚本通常分为三部分,其中BEGIN,END部分是可选部分;当只有BEGIN部分是可以没有输入文件。其中:

另外,awk作为编程语言,可以定义函数,可以包含注释(通常在文件中,以保持可读性和可重用性),使用#注释该字符所在的行(不包括之前的字符)。

BEGIN {action}
pattern {action}
END {action}

awk处理的基本流程:

  1. 按行读取(从文件或标准输入等),每一行称为一条记录record,使用$0表示;
    1.1 当文件缺省时,从标准输入中读取;使用Ctrl+D终止程序
  2. 对每一行执行SCRIPT,包括检查是否满足pattern,满足则执行action部分;其中:
    2.1 pattern省略是表示没有条件限制;
    2.2 action省略是表示执行{print}即打印当前记录,两者不可同时省略。

选项

常用的选项包括:

awk -F: '{print $1, $NF}' file.txt
# -F后的内容是正则表达式形式
awk -F '[.,:]' '{print $1, $NF}' file.txt
awk -v n=5 'BEGIN{for(i=0;i<n;i++) printf "%02d\n",i}'
awk --profile 'BEGIN{printf"---|Header|--\n"} {print} 
END{printf"---|Footer|---\n"}' marks.txt > /dev/null 

其他选项

SCRIPT之使用pattern过滤

例子:

awk 'BEGIN{print "----"} {print $1} END{print "-----"}'
awk '/^root/,/^adm/' /etc/passwd   

SCRIPT之使用action执行

pattern之后的{}的内容表示 action;当actiono多个时可以使用;或换行进行分隔。

这里先简单介绍print:
print表示输出,期间可以使用$数组, 字符串需要使用引号包围。

例子:

# $5即文件大小字段,$NF即文件名字段
# && 逻辑与;`/../`表示正则表达式; ~表示匹配
ls -l *|awk '$5>20 && $NF ~ /txt$/'

# 列出第1,3列
last -n 5 | awk '{print $1 "\t" $3}'

# 设置分隔符是:, 第3列值小于10是打印第1列(账号)和第3列(UID)
cat /etc/passwd | awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'
# 增加显示第一行(root);默认第一行是字段说明所以不直接处理
cat /etc/passwd | awk 'BEGIN{FS=":"} $3 < 10 {print $1 "\t " $3}'

# 复杂例子;从文件中读取awk
# test.awk中的内容
BEGIN{
    $1=1
    $2=1
    OFS=","
    for(i=3;i<=10;i++)
    {
        $i=$(i-2)+$(i-1)
    }
    print
}
# 打印斐波那契数列前10项
awk -f test.awk

# 定义变量
awk '{a=$1} {print a,$5}' file.txt
awk -v a="name" '{print a}'

# 使用数组
$ awk -F ':' '{a[$NF]++}END{for(i in a) print i,a[i]}' /etc/passwd

# 使用条件语句
netstat -antp | awk '{if($6=="LISTEN"){x++}else{y++}}END{print x,y}'

3 程序设计

内建变量

内建变量 说明
$0 当前处理记录(即当前读取的一行内容)
$1-$n 当前记录的第n个字段(列)
FS 字段/列分隔符,默认是空格或制表符
NF 当前记录的字段数目
NR 已经处理的记录条数,即当前行号
FNR 当前记录数,是每个文件的行号,NR是总数
RS 记录/行之间分隔符,默认是换行符\n
CONVFMT 数字转换格式 %.6g
OFS 输出字段分隔符,默认是空格
ORS 输出记录分隔符,默认是换行符\n
FIELDWIDTHS 输入字段宽度的空白分隔字符串
OFMT 数字的输出格式,%.6g
ARGC 命令行参数个数
ARGV 命令行参数数组
FILENAME 当前输入文件名字
ARGIND 当前被处理文件的ARGV标志符
ENVIRON UNIX/SHELL环境变量,数组形式
ERRNO UNIX系统错误消息
RSTART 被匹配函数匹配的字符串首
RLENGTH 匹配函数匹配的字符串长度
IGNRECASE 记录为真代表忽略大小写匹配
SUBSEP \0340x1C;文件分割符)
PROCINFO 当前运行程序进程信息数组

此外还有一些GNU awk扩展: 略

运算符

基本和C语言一致,基本的有:

例子:

awk 'BEGIN { a = 50; b = 20; print "(a + b) = ", (a + b) }'

控制语句

例子:来自

#  计算复利
#   输入: 钱数    利率    年数
#   输出: 复利值
{   i = 1
    while (i <= $3) {
        printf("\t%.2f\n", $1 * (1 + $2) ^ i)
        i = i + 1
    }
}

用户自定义函数

function function_name(argument1, argument2, ...) { 
   function body
}

例子:来自

# 脚本文件
# Returns minimum number
function find_min(num1, num2){
   if (num1 < num2)
   return num1
   return num2
}
# Returns maximum number
function find_max(num1, num2){
   if (num1 > num2)
   return num1
   return num2
}
# Main function
function main(num1, num2){
   # Find minimum number
   result = find_min(10, 20)
   print "Minimum =", result
  
   # Find maximum number
   result = find_max(10, 20)
   print "Maximum =", result
}
# Script execution starts here
BEGIN {
   main(10, 20)
}

调用外部shell程序/命令

例子:

# 管道方式
while (more stuff to do)
    print command | "/bin/sh"
close("/bin/sh")

# system函数
END { system("date | mail -s 'awk run done' root")}

4 内建函数

数学相关函数

字符串相关

awk -F: '{if(length($1)>=16) print}' /etc/passwd 
head -1 /etc/passwd|awk '{split($0,arr,/:/);for(i=1;i<=length(arr);i++) print arr[i]}'
echo 178278 world | awk 'sub(/[0-9]+/,"hello")'

时间

bit操作

其他(IO等)

上一篇 下一篇

猜你喜欢

热点阅读