如何在 bash shell 中 grep 某个文件的一部分

如何在 bash shell 中 grep 某个文件的一部分

我怎样才能“grep”某个字符串 1 的出现和某个字符串 2 的(第 N 次)出现之间的行。

例如

如果文件有行:

A

丙丁


弗格

公元前


我想要将行变为粗体(以 B 开头并以 E 结尾的行)。

可以使用 grep 或其他 Unix 命令行工具来完成此操作吗?

答案1

grep不太适合这个任务,你需要“向上”移动一个工具:

sed -n '/^B/,/^E/p' infile

输出:

B
C
D
E
B
C
E

关于第 N 个要求,我认为最简单的方法是再次“向上”推进一个工具,即 awk:

awk '/^B/ { f = 1; n++ } f && n == wanted; /^E/ { f = 0 }' wanted=2 infile

输出:

B
C
E

当遇到f时将设置标志,当发生时将取消设置,这与 sed 符号的工作方式非常相似。记录已经传递了多少个块,当为真时,将执行默认块()。/^B//^E/nf == 1 && n == wanted{ print $0 }

答案2

@Thor 的sed命令无法被打败,但我尝试通过以下perl脚本来解决括号中的问题部分:“... (第 N 次) 出现 ...”。

用法:

./script <start-regex> <end-regex> [N]

问题中的文件示例:

$ ./script "B" "E" < examplefile
B
C
D
E
B
C
E

$ ./script "B" "E" 2 < examplefile
B
C
D
E
F
G
B
C
E

没有任何错误检查或任何内容,并且脚本是非贪婪的,即,A B C D E E F只会B C D E使用 N=1 进行 grep。


#!/usr/bin/perl

if ($ARGV[2] != "") { $n = $ARGV[2] } else { $n = 1 }
$begin_str = $ARGV[0];
$end_str = $ARGV[1];

while(<STDIN>) {
  if($_ =~ $begin_str) { $flag=1 }             # beginning of match, set flag    
  if($_ =~ $end_str && $flag eq 1) { $i++ }    # i-th occurence of end string

  if($i eq $n) {                               # end of match after n occurences of end string
    $flag=2;
    $i=0; 
  }

  if ($flag ge 1) {                            # append currrent line to matching part
    $out.=$_;
  }

  if($flag eq 2) {                             # after detection of end of match, print complete match
    print $out;
    # print "---\n";                           # separator after a match
    $out="";
    $flag=0;
  }

}

相关内容