arrays - grep -B 模拟环形缓冲区/awk

标签 arrays bash awk grep

我需要在我的搜索字符串上方提取一行(例如,上方 19 行)。通常,我会选择

grep -B 19 $search_string $file | ...further processing

但是该脚本也应该适用于 Solaris,其中 grep 不提供 -B 选项。通常,如果我知道前面的行,我可以使用 awk '/begin/,/end/' 打印一堆行。在这种特殊情况下,这是不可能的。我尝试了以下方法:

1) 环形缓冲溶液。

#!/bin/bash
g_a_buffer=( 0 )
g_i_buffer_index=1
while read line
        do
        g_a_buffer[$((g_i_buffer_index % 20))]=$line
        echo $line|grep $search_string > /dev/null
        [ $? -eq 0 ] && echo ${g_a_buffer[$(( (g_i_buffer_index + 2) % 20))]}
        let "g_i_buffer_index += 1"
        done < $file_name

非常慢。对于大约 40k 行,它需要 1m37s(对于 grep 为 0.005s)

2) Awk 解决方案。我不得不直截了本地说,我是 awk 的极端初学者,很少超越 awk '{print $1}'。 下面一行行不通,但可以让您了解我要实现的目标:

awk '/mySearchString/ {print NR-19}' filename.txt 

执行0.118s,速度不错!但我得到的只是一个行号 - 19。我需要的是位于(第 - 19 行)的行的打印输出。经过一番谷歌搜索后,我仍然找不到答案。我承认这一定是一个非常基本的问题,但我似乎在这里碰壁了。

到目前为止我发现的是如何使用 awk(这是一种单行缓冲区)打印前一行,或者使用环形缓冲区但在 awk 中的大量实现。有没有更优雅的方法来做到这一点?

感谢您的帮助!

最佳答案

这是一个需要两次遍历文件的解决方案,因此不是最优的,但在实践中可能表现得很好。 (在 GNU awk 上测试过,但没有明显的原因表明它不能在 Solaris 上运行)。

awk "$(awk '/mySearchString/ { print "NR==" NR-19 }' myInputFile.txt)" myInputFile.txt

由于这需要两次传递,如果您从其他地方通过管道传输输入,您需要将其存储在某个地方的临时文件中。

或者,如果您知道您的搜索字符串在文件中最多出现一次(或者至少您只关心第一次出现),您可以将 awk 与 head 和 tail 结合使用以提取该行:

awk 'NR==1,/mySearchString/' | tail -n 19 | head -n 1

我手头没有合适的文本文件来对其进行基准测试,但我希望它比您的环形缓冲区解决方案好很多。

关于arrays - grep -B 模拟环形缓冲区/awk,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8386665/

相关文章:

Shell 脚本对文件中的行进行编号

javascript - 使用“下一步”按钮生成并循环随机数数组

regex - 使用 BASH 中的 shell 脚本在正则表达式上将一个大的 txt 文件拆分为 200 个较小的 txt 文件

linux - awk 在 bash 脚本中使用引号和空格

regex - sed 提取两个字符串之间的文本

linux - bash:通过连接 N 个字符串创建变量,其中 N 是脚本参数

arrays - swift 阵列。尝试根据当前时间查找数组中的下一个时间

javascript - 如何用空值预填充数组?

arrays - 将 3D 数组转换为 2D

python - 使用 argparse 传递参数后如何将 python 脚本作为批处理作业运行?