Linux AWK 学习笔记和心得

wolfgao · 2019年04月26日 · 最后由 Ricky. 回复于 2019年09月10日 · 2473 次阅读

AWK 真是一个强大的工具,如果要想使好 shell,这是一个必须征服的工具,比如 python 来说的确有时候让你感到崩溃,但是其实都是相同的,一旦掌握,就是必不可少的杀器。

  • 可以过滤字符串
  • 可以过滤文本文件,形成计算,输出结果
  • 可以和 shell 变量相互赋值,交互
  • 很方便进行计算,否则用 shell 的计算很别扭,反人道的。
  • 格式输出,形成报告 以下我就抛转一下,我们互相交流,有心得大家一起讨论,共同进步。

awk 语法

awk -F fs 'BEGIN{ } /pattern/ {action} END{ }' input-file ;-F 是指定分隔符
awk [选项参数] 'script' var=value file(s)awk [选项参数] -f scriptfile var=value file(s)

主要参数

  • -F fs or --field-separator fs 指定输入文件折分隔符,fs 是一个字符串或者是一个正则表达式,如-F:。
  • -v var=value or --asign var=value 赋值一个用户定义变量。
  • -f scripfile or --file scriptfile 从脚本文件中读取 awk 命令。

运算符

= += -= = /= %= = *= 赋值
?: C 条件表达式
|| 逻辑或
&& 逻辑与
~ ~! 匹配正则表达式和不匹配正则表达式
< <= > >= != == 关系运算符
空格 连接

  • - 加,减
  • / % 乘,除与求余
  • - ! 一元加,减和逻辑非 ^ *** 求幂 ++ -- 增加或减少,作为前缀或后缀 $ 字段引用 in 数组成员

模式匹配

  • 正则表达式:使用通配符的扩展集 使用正则,字符串匹配:~ 表示模式开始。// 中是模式。 比如: shell # 输出包含"re" 的行 $ awk '/re/ ' log.txt --------------------------------------------- 3 Are you like awk 10 There are orange,apple,mongo
  • 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试
    操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大刮号内,主要部分是:变量或数组赋值、输出命令、内置函数、控制流语句。

  • BEGIN 语句块, pattern 语句块, END 语句块
    awk 'BEGIN{ commands } pattern{ commands } END{ commands }' file
    awk 脚本通常由 BEGIN, 通用语句块,END 语句块组成,三部分都是可选的。 脚本通常是被单引号或双引号包住。
    BEGIN{ 这里面放的是执行前的语句 }
    END {这里面放的是处理完所有的行后要执行的语句 }
    {这里面放的是处理每一行时要执行的语句}
    例子 1:
    awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename

例子 2:
假设有这么一个文件(学生成绩表):

$ cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62

脚本:

$ touch cal.awk
awk -f
#运行前
BEGIN {
    math = 0
    english = 0
    computer = 0

    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
#运行中
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
    printf "---------------------------------------------\n"
    printf "  TOTAL:%10d %8d %8d \n", math, english, computer
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}

运行结果

$ awk -f cal.awk score.txt
NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL
---------------------------------------------
Marry  2143     78       84       77      239
Jack   2321     66       78       45      189
Tom    2122     48       77       71      196
Mike   2537     87       97       95      279
Bob    2415     40       57       62      159
---------------------------------------------
  TOTAL:       319      393      350
AVERAGE:     63.80    78.60    70.00

内建变量

变量 描述
$n 当前记录的第 n 个字段,字段间由 FS 分隔
$0 完整的输入记录
ARGC 命令行参数的数目
ARGIND 命令行中当前文件的位置 (从 0 开始算)
ARGV 包含命令行参数的数组
CONVFMT 数字转换格式 (默认值为%.6g) ENVIRON 环境变量关联数组
ERRNO 最后一个系统错误的描述
FIELDWIDTHS 字段宽度列表 (用空格键分隔)
FILENAME 当前文件名
FNR 各文件分别计数的行号
FS 字段分隔符 (默认是任何空格)
IGNORECASE 如果为真,则进行忽略大小写的匹配
NF 一条记录的字段的数目
NR 已经读出的记录数,就是行号,从 1 开始
OFMT 数字的输出格式 (默认值是%.6g)
OFS 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符
ORS 输出记录分隔符 (默认值是一个换行符)
RLENGTH 由 match 函数所匹配的字符串的长度
RS 记录分隔符 (默认是一个换行符)
RSTART 由 match 函数所匹配的字符串的第一个位置
SUBSEP 数组下标分隔符 (默认值是/034)

awk 中使用 shell 中的变量

一: "'$var'"

这种写法大家无需改变用'括起 awk 程序的习惯,是老外常用的写法.如:

var="test"
awk 'BEGIN{print "'$var'"}'

这种写法其实际是双括号变为单括号的常量,传递给了 awk.

如果 var 中含空格,为了 shell 不把空格作为分格符,便应该如下使用:

var="this is a test"
awk 'BEGIN{print "'"$var"'"}'

二: '"$var"'

这种写法与上一种类似.如果变量含空格,则变为'""$var""'较为可靠.

三: export 变量,使用 ENVIRON["var"] 形式,获取环境变量的值

例如:

var="this is a test"; export var;
awk 'BEGIN{print ENVIRON["var"]}'

四: 可以使用 awk 的-v 选项 (如果变量个数不多,个人偏向于这种写法)

例如:

var="this is a test"
awk -v awk_var="$var" 'BEGIN {print awk_var}'

这样便把系统变量 var 传递给了 awk 变量 awk_var.

awk 向 shell 变量传递值

“由 awk 向 shell 传递变量”,其思想无非是用 awk(sed/perl 等也是一样) 输出若干条 shell 命令,然后再用 shell 去执行这些命令。

eval $(awk 'BEGIN{print "var1='str1';var2='str2'"}')
或者
eval $(awk '{printf("var1=%s; var2=%s; var3=%s;",$1,$2,$3)}' abc.txt)
之后可以在当前 shell 中使用 var1,var2 等变量了。
echo "var1=$var1 ----- var2=$var2"

还有一种办法,使用 $() 来进行给 shell 变量赋值,如下:

val1=$(awk '{print $1}' abc.txt)

awk 进行计算

echo 4 7 | awk '{print $1*$2}'
28

共收到 1 条回复 时间 点赞

👍 很有参考价值,感谢

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册