首先使用 awk 处理最后一行

首先使用 awk 处理最后一行

我有一个数据文件,我想awk根据最后一个数据点使用它进行标准化。因此,我想先访问最后一个数据点,对数据进行标准化,然后正常处理。

下面的方法,使用tac两次,可以完成这项工作,但是,可能比必要的更复杂。

$ cat file
0 5
1 2
2 3
3 4
$ tac file | awk 'NR==1{norm=$2} {print $1, $2/norm}' | tac
0 1.25
1 0.5
2 0.75
3 1

我的问题是:仅使用awk是否可以获得上述结果?

我认为答案是“不,awk 逐行扫描文件”,但我愿意寻求替代方案的建议。

答案1

如果您的数据源是一个可以多次读取的文件(即它不是流),您应该首先使用tail(1)从最后一行获取您想要的数据,并将其传递给 awk 以对其进行顺序处理。tail将查找文件末尾以读取最后一行,而无需读取其之前的所有数据。

awk -v norm=$(tail -n 1 file | cut -d' ' -f2) '{print $1, $2/norm}' file

对于整个文件无法放入缓冲区缓存的大文件来说,这将是一个巨大的胜利(这意味着需要从磁盘读取两次,每次传递一次),并且无需扫描,将在较小程度上有所帮助输入到达最后一行。较小的文件可能与两遍方法没有太大区别。

答案2

您可以在 awk 中将其作为两遍解决方案:

awk 'FNR == NR { n = $2; next } { print $1, $2/n }' infile infile

如果您的 awk 版本支持 ENDFILE 块(例如 GNU awk 4+),您可以这样做:

awk 'ENDFILE { n = $2 } FNR != NR { print $1, $2/n }' infile infile

seek请注意,先到文件末尾查看效率更高卡姆的回答

解释

第一个示例的工作原理是记住前面的$2,即仅当本地行计数器 ( FNR) 等于全局行计数器 ( NR) 时才对其进行计算。该next命令跳到下一行,在这种情况下,它确保仅在解析第二个参数时才评估最后一个块。

第二个示例具有类似的逻辑,但利用了 ENDFILE 块,该块在到达输入文件末尾时进行评估。

答案3

您可以将它们加载到数组中并向后读取:

awk '{x[i++]=$0} END{for (j=i-1; j>=0;) print x[j--] }'

您可以更有效地完成此操作,但这说明了为什么awk这不是正确的工具。继续使用tac可用的地方,GNU tac 通常是完成这项工作的各种工具中最快的。

相关内容