现在:
我是脚本编写新手,边学边学,这是我开发的第一个脚本。我的脚本试图查看指定的文件,扫描文件以查找单词“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 }'