首先使用 awk 处理最后一行

Ber*_*ard 11 awk text-processing

我有一个数据文件,我想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
Run Code Online (Sandbox Code Playgroud)

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

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

cam*_*amh 6

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

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

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


Tho*_*hor 5

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

awk 'FNR == NR { n = $2; next } { print $1, $2/n }' infile infile
Run Code Online (Sandbox Code Playgroud)

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

awk 'ENDFILE { n = $2 } FNR != NR { print $1, $2/n }' infile infile
Run Code Online (Sandbox Code Playgroud)

请注意,seek首先查看文件末尾的camh's answer效率更高。

解释

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

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