从文本文件的某个点打印前 20 行文本

从文本文件的某个点打印前 20 行文本

现在:

我是脚本编写新手,边学边学,这是我开发的第一个脚本。我的脚本试图查看指定的文件,扫描文件以查找单词“Error”。目前,它会将文件从“ERROR”点开始的其余部分打印到输出文件中。

问题:

在文件中找到单词“ERROR”后,如何将从单词“ERROR”开始的前 20 行文本打印到输出文件,并将从“ERROR”点开始的其余文件附加到同一个输出文件?

可能的解决方案?

我会在这里使用某种循环来执行此操作吗?我脑子里有 sudo code=,知道如何执行此操作,但不确定如何实际实现。有人可以建议或告诉我是否有更好的方法来做到这一点吗?

脚本:

my $file_handle = IO::File->new ('output','a') or die;

print $file_handle "*****************************\n";

while(<>) {

        print $file_handle $_ if(/.*ERROR/ .. /^XXX/);

        }

答案1

您可以使用( ) 选项执行grep此操作:-B--before-context

grep -B 20 error filename

答案2

awk:我在本演示中只保留 5 行,将“保留”值调整为 20

{ seq 10; echo ERROR; seq 6; } |
awk -v keep=5 '
  /ERROR/ {
    for (i=keep; i>=1; i--) print lines[i]  # the stored lines
    print                                   # the current line
    while (getline > 0) print               # all the remaining lines
  }
  {
    # remember the previous "keep" lines.
    for (i=keep; i>1; i--)
      lines[i] = lines[i-1]
    lines[1] = $0
  }
'
6
7
8
9
10
ERROR
1
2
3
4
5
6

另一种方法:读取文件两次,但我认为这样更清晰。

keep=20
lineno=$(sed -n '/ERROR/{=;q;}' file)
[[ -n $lineno ]] && sed -n "$((lineno-keep)),\$p" file

答案3

如果我在 bash 中执行此操作,我会执行以下操作:

line=$(grep -m1 -n ERROR the_file | cut -f1 -d:)
if ((line <= 20)); then
  cat the_file;
else
  tail -n+$((line-20)) the_file
fi

grep与“显示行号”选项一起使用来获取匹配的行号,然后tail -n从前第 20 行开始打印,注意避免使用负的起始行号。

在任何其他语言中,解决方案都是保留一个滚动(可能是循环)缓冲区,用于保存最后读取的 20 行。例如,在 awk 中,使用循环缓冲区:

awk -v P=20 'found  { print; next }
             /ERROR/{ for (i=NR+1;i<=NR+P;++i) 
                        if (i%P in saved)
                          print saved[i%P]
                      found = 1
                    }
                    { saved[NR%P] = $0 }'

相关内容