如果满足条件,则打印上一行

时间:2015-01-02 10:49:57

标签: linux awk grep

我想grep一个单词,然后找到该行中的第二列,并检查它是否大于一个值。是的,我想打印上一行。

例如:

输入文件

AAAAAAAAAAAAA
BB  2
CCCCCCCCCCCCC
BB 0.1

输出

AAAAAAAAAAAAA

现在,我想搜索BB,如果该行中的第二列(2或0.1)大于1,我想打印上一行。

有人可以用grep和awk帮我吗?谢谢。任何其他建议也欢迎。感谢。

4 个答案:

答案 0 :(得分:16)

这可以是一种方式:

$ awk '$1=="BB" && $2>1 {print f} {f=$1}' file
AAAAAAAAAAAAA

解释

  • $1=="BB" && $2>1 {print f}如果第一个字段正好是BB且第二个字段大于1,则打印f,即存储值。
  • {f=$1}将当前行存储在f中,以便在阅读下一行时可以访问该行。

答案 1 :(得分:4)

另一种选择:如果条件匹配,则反转文件并打印下一行行:

tac file | awk '$1 == "BB" && $2 > 1 {getline; print}' | tac

答案 2 :(得分:1)

关于普遍性

我认为需要提及的是,此类问题的最通用解决方案涉及两个步骤:

  • 第一次通过将十进制行号($ REC)添加到每行的开头,从而通过$ REC有效地将行分组为记录
  • 在第二个遍历上以$ REC的每个新值作为记录边界触发第一遍(重置$ CURREC),此后沿原生AWK习惯用法滚动,涉及与记录相匹配的$ CURREC。

在中间文件中,某些十进制数字序列后跟一个分隔符(出于人为原因,通常是添加了制表符或空格)被解析(相对于概念文件而言是带外的),相对于基线文件而言是带外的。

命令行粘贴怪物

即使仅限于命令行,确保中间文件从不击中磁盘也很容易。您只需要使用支持过程替换的高级外壳程序,例如ZSH(我自己的最爱):

paste <( <input.txt awk "BEGIN { R=0; N=0; } /Header pattern/ { N=1; } { R=R+N; N=0; print R; }" ) input.txt | awk -f yourscript.awk 

让我们展示一种更适合展示的方式:

P="/Header pattern/"
X="BEGIN { R=0; N=0; } $P { N=1; } { R=R+N; N=0; print R; }"
paste <( <input.txt awk $X ) input.txt | awk -f yourscript.awk 

这将启动三个过程:简单的内联AWK脚本paste,以及您真正想首先运行的AWK脚本。

在幕后,<()命令行结构创建一个命名管道,并将要粘贴的管道名称作为其第一个输入文件的名称传递。对于paste的第二个输入文件,我们将其命名为原始输入文件的名称(因此,该文件由两个不同的进程依次并行读取,这两个进程之间最多使用一个< / strong>从磁盘读取(如果输入文件很冷)。

中间名为魔术的管道是一个内存中的FIFO,古代Unix可能以平均大小约16 kB进行管理(如果paste进程耗时缓慢,则间歇地暂停yourscript.awk进程此FIFO向下)。

也许现代的Unix可以在其中投入更大的缓冲区,但这肯定不是您应该关注的稀缺资源,直到您编写第一个 truly 高级命令行并进行涉及这些进程的重定向成千上万:-)

其他性能注意事项

在现代CPU上,所有这三个进程都可以轻松地发现自己在单独的内核上运行。

这些过程中的前两个过程确实很琐碎:一个具有单个模式匹配和一些次要簿记的AWK脚本,并粘贴带有两个参数的调用。 yourscript.awk的运行速度将比这些更快。

什么,您的开发机器没有轻松加载的内核来在执行域中几乎免费提供此主shell-master解决方案模式?

响,响。

你好?

嘿,这是给你的。 2018年刚刚来临,并希望解决问题。

2020年正式成为MTV的死因:这就是我们喜欢的方式,一无所有的魔力管道和免费的核心。不要大声说出最近正在摇摇欲坠的任何特定TLA芯片供应商。

作为最终的性能考虑,如果您不希望解析实际记录号的开销:

X="BEGIN { N=0; } $P { N=1; } { print N; N=0; }"

现在,在in-FIFO中间文件中,每行仅附加两个字符(“ 0”或“ 1”,并由paste添加默认分隔符),其中“ 1”首先标记记录中的行。

命名FIFO

在后台,这些与您编写任何常规管道命令时Unix实例化的魔术FIFO没什么不同:

cat file | proc1 | proc2 | proc2 

三个未命名的管道(甚至不需要使用专门用于cat的整个过程)。

几乎不幸的是,由shell预先管理的默认stdin / stdout流的真正 exception 便利性掩盖了paste $magictemppipe1 $magictemppipe2在99年没有值得考虑的其他性能考量的现实。在所有情况下所占的百分比。

“使用<() Y型关节,卢克。”

您对问题域中自然语义分解的本能反射将极大地受益。

如果首先有人愿意将壳结构<()命名为YODA运算符,我怀疑它至少在坚实的十年前就已被推向通用服务。

答案 3 :(得分:0)

结合sed和awk,您将获得以下信息: sed 'N;s/\n/ /' < file |awk '$3>1{print $1}'

sed 'N;s/\n/ /:合并第一行和第二行,并用空格替换下一行字符

awk '$3>1{print $1}':如果$ 3(第3列的值大于1)则打印$ 1(第1列)