因此,我有一个 CSV 文件中的航班数据集,我想获取按天排序的延误航班的百分比(第 6 列)。 0 表示不延迟,1 表示延迟 15 分钟或以上。
输入:
DAY_OF_MONTH,"DAY_OF_WEEK","ORIGIN","DEST","DEP_TIME","DEP_DEL15","CANCELLED","DIVERTED","DISTANCE"
1,Tuesday,ORD,GRB,1003,0.00,0.00,0.00,322.248
1,Tuesday,TUL,ORD,1027,0.00,0.00,0.00,1083.42
1,Tuesday,EWR,TYS,1848,0.00,0.00,0.00,1168.61
输出:
Weekday, % delayed, delayed, total flights
Tuesday,0.00,0,3
该数据集实际上有很多行,并且有一个月中的每一天及其所有航班,因此这不是实际的输出。
有人帮我想出了:
#!/bin/awk
BEGIN { FS = OFS = "," }
FNR > 1 { total[$2]++; if ($6) delay[$2]++ }
END {
print "\"weekday\"", "\"percentage_delayed\"", "\"delayed\"", "\"total_flights\""
for ( day in total ) { print day, delay[day] / total[day] * 100, delay[day], total[day]}
}
答案1
当#!/bin/awk
你告诉 awk 使用姓名包含脚本的文件作为脚本而不是内容包含脚本的文件的名称。就像写:
awk './delayed_by_day_jan20.awk'
代替:
awk -f './delayed_by_day_jan20.awk'
就像在命令行上指定包含 awk 脚本的文件一样,您-f
也必须在 shebang 中使用来告诉 awk 打开它传递的文件名(即当前脚本文件的名称)并将其内容用作 awk 脚本来解释。
话说回来....
将您在 Unix 中编写的每个命令视为只是一个命令。该命令是否用 awk、perl、shell 或其他任何语言编写并不重要 - 它应该根据它的内容来命名做,而不是它是如何实现的。鉴于此,您绝对不应该使用以.awk
or.sh
或.perl
或其他任何形式结尾的命令,以指示它们所使用的语言,以便除其他外,您可以将在 awk 中编写的任何命令重新实现为 perl,反之亦然,而无需必须检查调用该命令的所有其他命令才能更改它们。所以你的命令名称应该是delayed_by_day_jan20
,而不是delayed_by_day_jan20.awk
。
另外,其他人不同意这一点,因为他们喜欢使用理解 awk 语法的编辑器,但在我看来,你永远不应该使用 shebang 来调用 awk,只需使用 shebang 来调用你使用的任何 shell,然后在你的 shell 脚本中简单地调用 awk 即可就像您从命令行调用它一样。这将大大降低脚本的复杂性,对于那些极其常见的情况,在 awk 中完成大部分工作很有用,但在 shell 中完成部分工作也很有用,例如验证输入文件的存在、创建临时文件、设置陷阱、将命令参数分隔成awk 变量赋值与 awk 参数等。参见https://stackoverflow.com/a/61002754/1745001和谷歌“awk shebang”有关这些问题的更多信息。
以下是编写 shell 脚本的方法:
$ cat delayed_by_day_jan20
#!/usr/bin/env bash
awk '
BEGIN { FS = OFS = "," }
FNR > 1 { total[$2]++; if ($6) delay[$2]++ }
END {
print "\"weekday\"", "\"percentage_delayed\"", "\"delayed\"", "\"total_flights\""
for ( day in total ) {
printf "%s,%0.2f,%d,%d\n", day, delay[day] / total[day] * 100, delay[day], total[day]
}
}
' "${@:--}"
$ ./delayed_by_day_jan20 file
"weekday","percentage_delayed","delayed","total_flights"
Tuesday,0.00,0,3
现在只需修复您的 awk 脚本以执行您希望它执行的任何操作(如果不是这样的话),如果您在执行此操作时遇到麻烦,请提出一个新问题。