【问题标题】:How to print 5 consecutive lines after a pattern in file using awk [duplicate]如何使用awk在文件中的模式后打印5个连续行[重复]
【发布时间】:2011-07-16 01:15:25
【问题描述】:

我想在文件中搜索一个模式并在找到该模式后打印 5 行。

我需要使用awk 来执行此操作。

例子:

文件内容:

.
.
.
.
####PATTERN#######
#Line1
#Line2
#Line3
#Line4
#Line5
.
.
.

如何解析文件并仅打印上述行? 我是否使用包含“PATTERN”的行的 NR 并保持递增到 5 并在此过程中打印每一行。 请让我知道在 Awk 中是否有任何其他有效的方法。

【问题讨论】:

标签: shell unix awk


【解决方案1】:

在 AWK 中的另一种方法:

awk '/PATTERN/ {for(i=1; i<=5; i++) {getline; print}}' inputfile

sed:

sed -n '/PATTERN/{n;p;n;p;n;p;n;p;n;p}' inputfile

在 GNU 中 sed:

sed -n '/PATTERN/,+7p' inputfile

sed -n '1{x;s/.*/####/;x};/PATTERN/{:a;n;p;x;s/.//;ta;q}' inputfile

# 字符代表一个计数器。使用比您要输出的行数少一。

【讨论】:

  • 很好地利用了保持空间作为倒计时。
  • 如果我只想匹配最后一列的模式怎么办?例如,如果最后一列 ($NF) 是 E,则打印下一行。我想忽略其他列中的 E。
  • @lovedynasty: awk '$NF ~ /^E$/ {for(i=1; i&lt;=5; i++) {getline; print}}' inputfile 应该可以工作。
  • 如果您打算使用 sed (Gnu sed),那么 sed -n /PATTERN/,+5p' file 可能符合要求。或sed -n /PATTERN/{N;N;N;N;N;p}' file.
  • @Kjuly:请注意,potong's 使用大写 N's 附加到模式空间(较低的 n 替换模式空间)。
【解决方案2】:
awk '
{ 
    if (lines > 0) {
        print;
        --lines;
    }
}

/PATTERN/ {
    lines = 5
}

' < input

这会产生:

#Line1
#Line2
#Line3
#Line4
#Line5

【讨论】:

  • 此代码存在问题。如果 PATTERN 在少于 5 行后重复,则循环重新开始,而不是完成打印所有 5 行。丹尼斯的回答效果更好。
  • @Ruchi 你是对的。丹尼斯是一个更好的答案(我赞成)。我认为它是在@tomkaith13 接受我自己的之后出现的。我只能假设我的回答解决了他的问题,即使它不是最有弹性的。
  • @Ruchi:但在这种情况下,丹尼斯的回答并没有打印出第二次出现之后的所有 5 行。我认为这取决于你想要什么。您可能希望在第二次出现后打印第一行(在前一次的 5 行范围内)两次:第一次(包括第二次出现)一次,第二次出现两次。这实际上取决于用例,并且没有由 OP 指定。
  • 如果我只想匹配最后一列的模式怎么办?例如,如果最后一列 ($NF) 是 E,则打印下一行。我想忽略其他列中的 E
  • @lovedynasty:这是一个不同的问题,应该作为新帖子提出。你试过$NF ~ /PATTERN/ { 吗?
【解决方案3】:

如果决定给 grep 一个机会,grep "PATTERN" search-file -A 5 将为您完成这项工作。

编辑:您也可以在 awk 脚本中使用 system() 函数调用 grep。

【讨论】:

  • 我也这么认为。但这会产生包含“PATTERN”的行,这似乎不符合要求。
  • @Johnsyweb: grep -A6 | tail -5 ?
  • 我认为 grep -A 是一个 gnu 扩展,您在 AIX 或 Solaris 标准安装中找不到该选项,但我现在无法访问这些操作系统来确认这一点。亲切地
  • 您也可以在其他 unix 上安装 gnu utils。非常整洁的信息谢谢。定期使用 grep 但不知道它有 -A 和 -B
  • @Johnsyweb:除了匹配PATTERN 的初始行之外,grep -A5 将产生与您的代码相同的输出。但是,由于多次出现,事情变得更加复杂。
【解决方案4】:

awk 来救援!

用图案线打印(共6行)

$ awk '/^####PATTERN/{c=6} c&&c--' file

####PATTERN#######
#Line1
#Line2
#Line3
#Line4
#Line5

跳过模式并打印接下来的五行

$ awk 'c&&c--; /^####PATTERN/{c=5}' file

#Line1
#Line2
#Line3
#Line4
#Line5

【讨论】:

  • 对丹尼斯的回答有很好的改进!
  • @karakfa,在 awk awk 'c&amp;&amp;c--; /^####PATTERN/{c=5}' 中从未见过模式之前的语句。我们可以在 print 或 assignment 等模式之前写任何类型的语句吗?
  • 不是语句,而是任何具有值的表达式(将被解释为真值)。与表达式对应的语句将是默认语句,即{print}
【解决方案5】:

编辑:没有注意到 PATTERN 不应该是输出的一部分。

cat /etc/passwd | awk '{if(a-->0){print;next}} /qmaild/{a=5}'

cat /etc/passwd | awk ' found && NR-6 < a{print} /qmaild/{a=NR;found=1}'

我能想到的最短的是:

cat /etc/passwd | awk 'a-->0;/qmaild/{a=5}'

读取为 a 趋于 0。/qmaild/ 将 a 设置为 5 :-)

【讨论】:

  • 很好地使用了--&gt; 运算符!但是你为什么使用cat
  • 将输入与 OP 感兴趣的命令明确分开。
  • 对于经验不足的读者来说,--> 肯定是附加到“a”变量的--运算符,> 表示“大于”,是吗? awk 可以解析这种连接的语法。不错!
【解决方案6】:

快速解决方案:awk '/PATTERN/ {i=0} { if (i&lt;=5) {print $0}; i+=1} BEGIN {i=6}'

【讨论】:

    【解决方案7】:

    与 Johnsyweb 的解决方案一样有限,但使用了不同的方法和 GNU awk 的高级功能,允许完整的 RegEx 记录分隔符导致一段代码,恕我直言,非常 awk-ish:

    awk -F\\\n '{NF=5}NR-1' RS="PATTERN[^\n]*." OFS=\\\n
    

    因此,如果您想要一个稳定且可读的解决方案,请遵循 Dennis Williamson 的答案(+1 表示该答案),但也许您在查看这样的行时也只是享受 awk 的美丽。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-30
      • 1970-01-01
      • 2018-04-11
      • 1970-01-01
      • 1970-01-01
      • 2020-05-25
      相关资源
      最近更新 更多