【问题标题】:Grep for next blank line after line number行号后的下一个空白行的Grep
【发布时间】:2013-01-11 09:33:38
【问题描述】:

我有一个大文件,其中包含不同制表符分隔数据的表格。不同的表用空行分隔。

我有一个特定表格开头的行号,我需要检索整个表格。

如何使用 grep(或类似的东西)来获取特定行号之后下一个空白行的行号?

【问题讨论】:

  • 您要检索表格还是只检索下一个空白行 nr??

标签: linux shell sed grep


【解决方案1】:

为此使用sed,这应该可以解决问题:

sed -n '1,/^\s*$/p' file

只需替换逗号前的第一个数字,在这种情况下1 用行号,演示从给定的行号打印每个表:

$ cat file
one
two
three

five
six
seven

nine
ten
eleven

$ sed -n '1,/^\s*$/p' file
one
two
three

$ sed -n '5,/^\s*$/p' file
five
six
seven

$ sed -n '9,/^\s*$/p' file
nine
ten
eleven

使用-n 选项关闭每行的默认打印,p 标志sed 从行号打印到与正则表达式匹配的第一行,其中:

^     # Matches the start of the line
\s*   # Matches zero or more whitespace characters
$     # Matches the end of the line

使用sed -n 'A,Bp' 格式,其中AB 可以是行号或正则表达式,您可以轻松打印文件的子部分。

sed 只打印下一个空行的行号:

$ sed -n '1,/^\s*$/{=}' file | tail -1
4

$ sed -n '5,/^\s*$/{=}' file | tail -1
8

$ sed -n '9,/^\s*$/{=}' file | tail -1
12

或者只是打印所有空白行的位置

$ sed -n '/^\s*$/{=}' file
4
8
12

使用awk 获取下一个空白行号不需要使用tail

$ awk 'NR>=1 && /^\s*$/{print NR;exit}' file
4

$ awk 'NR>=5 && /^\s*$/{print NR;exit}' file
8

$ awk 'NR>=9 && /^\s*$/{print NR;exit}' file
12

$ awk '/^\s*$/{print NR}' file
4
8
12

如果它让您更清楚,您可以使用 awk 使用 -v 传递一个变量

$ awk -v start=1 'NR>=start && /^\s*$/{print NR;exit}' file
4

$ awk -v start=5 'NR>=start && /^\s*$/{print NR;exit}' file
8

$ awk -v start=9 'NR>=start && /^\s*$/{print NR;exit}' file
12

【讨论】:

  • 那么起跑线会去哪里?
  • @JacobTomlinson 我已经更新了我的答案,它应该包含你需要的一切。
  • 很好的答案和解释。只是一条评论,他个人提到“大文件”我觉得sed -n '5,$p; /^\s*$/q' 当然会更好,如果这取决于他的文件有多大。但您可以使用 seq 99999999999|sed ... 进行测试
  • @Kent 你测试了吗?那行不通我想你的意思是sed -n '5,${p;/^\s*$/q}',我理解你的意思,但非常怀疑你尝试的方法会节省任何时间。
  • 大文件可能有点夸大其词。它大约有4000行。但是感谢您的回答,它非常优雅地解决了我的问题。
【解决方案2】:

Perl 使这变得简单。将第 31 行的所有行提取到 some_file 中的下一个空白行:

$ perl -wne 'print if 31 .. /^$/' some_file

【讨论】:

    【解决方案3】:

    awk 的一种方式:

    awk -vs=$sta '{ok=NR>=s}ok&&!$0{exit;}ok&&$0'
    

    $sta 是一个变量,存储起始行号。如果我们用起始行 nr=5 的 sudo_O 的输入示例进行测试,它看起来像:

    kent$  sta=5
    
    kent$  echo "1
    2
    3
    
    5
    6
    7
    
    9
    10
    11"|awk -vs=$sta '{ok=NR>=s}ok&&!$0{exit;}ok&&$0'
    5
    6
    7
    

    注意sed的地址会包含边界,也就是说,目标表后面的空行也会被打印出来。这个 awk one-liner 不会打印它。好吧,这取决于您想要输出的内容。

    编辑以防您只想获取下一个空行号

    awk -vs=$sta 'NR>=s&&!$0{print NR;exit;}' file
    

    【讨论】:

      【解决方案4】:

      下面的命令 5 是您已知的表格行号

      perl -lne 'exit if(/^$/ && $.>5);if($.>=5){print}' your_file
      

      【讨论】: