В настоящее время:

Я новичок в написании сценариев, обучаю себя по ходу дела, и это мой первый сценарий, который я разрабатываю. То, что пытается сделать мой скрипт - это посмотреть на указанный файл, отсканировать файл, чтобы найти слово "Ошибка". В настоящее время он печатает остальную часть файла из точки "ОШИБКА" в выходной файл.

Проблема:

После нахождения слова "ОШИБКА" в файле, как я могу напечатать предыдущие 20 строк текста из слова "ОШИБКА" в выходной файл и добавить оставшуюся часть файла из точки "ОШИБКА" в тот же выходной файл?

Возможное решение?

Буду ли я использовать какой-то цикл здесь, чтобы сделать это? У меня есть код sudo = в моей голове, чтобы понять, как это сделать, но я не уверен, как это реализовать. Кто-нибудь может посоветовать или сказать мне, если есть лучший способ сделать это?

Автор сценария:

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

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

while(<>) {

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

        }

3 ответа3

3

Вы можете сделать это с помощью опции grep 's -B (--before-context):

grep -B 20 error filename
0

awk: я просто держу 5 строк для этой демонстрации, установите значение "keep" на 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

Другой подход: занимает 2 чтения файла, но, я думаю, он понятнее.

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

Если бы я делал это в 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 с опцией "show line numbers" ·, чтобы получить номер строки совпадения, а затем 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 }'

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .