awk笔记

19 篇文章 0 订阅

快速上手

内建变量与打印

  • NF(可以理解为Number of fields)
    • 内建变量,表示当前行的字段数量
    • {print NF, $1, $NF}
  • NR(可以理解为Number of rows)
    • 内建变量,表示当目前为止读到的行数。
  • 打印文本
    • 在 print 语句中, 被双引号包围的文本会和字段, 以及运算结果一起输出.
    • {print "total pay for"}
  • printf
    • { printf("total pay for %s is $%.2f\n", $1, $2 * $3) }
    • { printf("%-8s $%6.2f\n", $1, $2 * $3) }
  • 输出排序
    • awk '{ printf("%6.2f %s\n", $2 * $3, $0) }' emp.data | sort -n

选择

打印那些报酬超过 50 的
$2 * $3 > 50 { printf("$%.2f for %s\n", $2 * $3, $1) }

打印所有第一个字段是Susie 的行:
$1 == "Susie"

通过正则表达式, 打印所有包含 Susie 的行
/Susie/

模式组合

模式可以使用括号和逻辑运算符进行组合, 逻辑运算符包括 &&, ||, 和 !。

打印那些 $2 至少为 4, 或者 $3 至少为 20 的行:

$2 >= 4 || $3 >= 20

两个条件都满足的行只输出一次. 将这个程序与下面这个程序作对比, 它包含两个模式,如果某行对这两个条件都满足, 它会被打印两次:

$2 >= 4
$3 >= 20

打印不满足($2 小于 4, 并且 $3 也小于 20)的行

!($2 < 4 && $3 < 20)
数据验证

真实的数据总是存在错误. 检查数据是否具有合理的值, 格式是否正确, 这种任务通常称作数据验证 (data
validation), 在这一方面 awk 是一款非常优秀的工具.
数据验证在本质上是否定: 不打印具有期望的属性的行, 而是打印可疑行. 接下来的程序使用比较模式, 将
5 条合理性测试应用到 emp.data 的每一行:

NF != 3 { print $0, "number of fields is not equal to 3" }
$2 < 3.35 { print $0, "rate is below minimum wage" }
$2 > 10 { print $0, "rate exceeds $10 per hour" }
$3 < 0 { print $0, "negative hours worked" }
$3 > 60 { print $0, "too many hours worked" }

如果数据没有错误, 就不会有输出。

BEGIN 与 END

特殊的模式 BEGIN 在第一个输入文件的第一行之前被匹配, END 在最后一个输入文件的最后一行被处理
之后匹配. 这个程序使用 BEGIN 打印一个标题:

BEGIN { print "NAME RATE HOURS"; print "" }
{ print }

可以在同一行放置多个语句, 语句之间用分号分开。注意 print "" 打印一个空行, 它与一个单独的 print
不相同, 后者打印当前行

计算

awk可以用来进行简单的数学或字符串计算,而且可以使用内建变量、自定义变量来计算和存储数据。
awk 中, 用户创建的变量不需要事先声明就可以使用。

计数

用一个变量 emp 计算工作时长超过 15 个小时的员工人数:

$3 > 15 { emp = emp + 1 }
END { print emp, "employees worked more than 15 hours" }
总和与平均数

利用 NR 来计算平均报酬:

{ pay = pay + $2 * $3 }
END { print NR, "employees"
	  print "total pay is", pay
	  print "average pay is", pay / NR
}

很明显, printf 可以用来产生更加美观的输出. 这个程序有一个潜在的错误: 一种不常见的情况是 NR 的值为
0, 程序会尝试将 0 作除数, 此时 awk 就会产生一条错误消息。

字符串拼接

可以通过旧字符串的组合来生成一个新字符串; 这个操作叫作拼接 (concatenation).

{ names = names $1 " " }
END { print names }
打印最后一行

虽然在 END 动作里, NR 的值被保留了下来, 但是 $0 却不会。
打印文件最后一行

{ last = $0 }
END { print last }
内建函数

awk 也提供用来计算其他值的内建函数. 求平方根, 取对数, 随机数, 除了这些数学函数, 还有其他用来操作文本的函数. 其中之一是 length, 它用来计算字符串中字符的个数.

计算每一个人的名字的长度:

{ print $1, length($1) }
行,单词与字符的计数

使用 length, NF 与 NR 计算行, 单词与字符的数量, 为方便起见, 我们将每个字段都当成一个单词

{ nc = nc + length($0) + 1
nw = nw + NF
}
END { print NR, "lines,", nw, "words,", nc, "characters" }

流程控制语句

Awk 提供了用于决策的 if-else 语句, 以及循环语句, 所有的这些都来源于 C 语言. 它们只能用在动作(Action) 里。

if else
$2 > 6 { n = n + 1; pay = pay + $2 * $3 }
END { if (n > 0)
	print n, "employees, total pay is", pay,
			 "average pay is", pay/n
else
	print "no employees are paid more than $6/hour"
}
while

一个 while 含有一个条件判断与一个循环体. 当条件为真时, 循环体执行。

{ i = 1
	while (i <= $3) {
		printf("\t%.2f\n", $1 * (1 + $2) ^ i)
			i = i + 1
	}
}
for

大多数循环都包括初始化, 测试, 增值, 而 for 语句将这三者压缩成一行。

{ for (i = 1; i <= $3; i = i + 1)
	  printf("\t%.2f\n", $1 * (1 + $2) ^ i)
}

数组

一个简单的例子。
下面这个程序按行逆序显示输入数据.。第一个动作将输入行放入数组 line 的下一个元素中;
也就是说, 第一行放入 line[1], 第二行放入 line[2], 依次类推.。
END 动作用一个 while 循环, 从数组的最后一个元素开始打印, 一直打印到第一个元素为止。

{line[NR] = $0}
END { i = NR
		while(i > 0){
			print line[i]
			i = i-1
		}
	}

用for循环实现等价程序:

{ line[NR] = $0 } # remember each input line
END { for (i = NR; i > 0; i = i - 1)
	print line[i]
}

实用“一行”手册

虽然 awk 可以写出非常复杂的程序, 但是许多实用的程序并不比我们目前为止看到的复杂多少。
这里有一些小程序集合, 对读者应该会有一些参考价值. 大多数是我们已经讨论过的程序的变形。

  1. 输入行的总行数
    END { print NR }
  2. 打印第10行
    NR == 10
  3. 打印每一个输入行的最后一个字段
    { print $NF }
  4. 打印最后一行的最后一个字段
    { field = $NF }
    END { print field }
    
  5. 打印字段数多余4个的输入行
    NF>4
  6. 打印最后一个字段值大于4的输入行
    $NF >4
  7. 打印属于输入行的字段数的总和
    { nf = nf + NF }
    END { print nf }
    
  8. 打印包含Beth的行的数量
    /Beth/ { nlines = nlines + 1 }
    END { print nlines }
    
  9. 打印具有最大值的第一个字段,以及包含它的行(假设$1总是正的)
$1 > max { max = $1; maxline = $0 }
END { print max, maxline }
  1. 打印至少包含一个字段的行
    NF > 0
  2. 打印长度超过80个字符的行
    length($0) > 80
  3. 在每一行的前面加上它的字段数
    { print NF, $0 }
  4. 打印每一行的第1与第2个字段,但顺序相反
    {print $2, $1}
  5. 交换每一行的第1与第2个字段,并打印该行
    { temp = $1; $1 = $2; $2 = temp; print}
  6. 将每一行的第一个字段用行号代替
    { $1 = NR; print }
  7. 打印删除了第2个字段后的行
    { $2 = ""; print }
  8. 将每一行的字段按逆序打印
    { for(i=NF; i>0; i=i-1)
    	printf("%s ", $i)
      printf("\n")
    }
    
  9. 打印每一行的所有字段值之和
    { sum = 0
      for(i=1; i<= NF; i=i+1) sum = sum + $i
      print sum
    }
    
  10. 将所有行的所有字段值累加起来
    { for (i = 1; i <= NF; i = i + 1) sum = sum + $i }
    END { print sum }
    
  11. 将每一行的每一个字段用它的绝对值替换
    { for (i = 1; i <= NF; i = i + 1) if ($i < 0) $i = -$i
    print
    }
    

系统学习

  • 待办
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

barbyQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值