Как распечатать файл, начиная с N-го вхождения строки
В работе с текстовыми файлами нередко возникает задача извлечения данных, начиная с определенного вхождения слова или строки. В этой статье мы рассмотрим, как распечатать файл, начиная с второго или N-го появления строки "бинго", с использованием различных инструментов.
Приведение примера файла
Предположим, у вас есть текстовый файл со следующим содержимым:
12
234
bingo
1
bingo
572
22
Задача: вывод данных с N-го вхождения
При данной задаче необходимо распечатать файл, начиная с 2-го появления строки "bingo". Ожидаемый вывод следующий:
bingo
572
22
Решение с использованием grep
и tail
Одно из возможных, но не самых эффективных решений можно предложить с помощью комбинации команд grep
и tail
. Пример команды:
grep --after-context=999999999 'bingo' file.txt | tail +2 | grep --after-context=999999999 'bingo'
Хотя это и работает, это не самый оптимальный способ, особенно если в файле много строк.
Использование Perl для решения задачи
Более эффективным вариантом является использование Perl. С помощью одной строки кода можно добиться необходимого результата:
perl -ne '$found++ if /^bingo/; print if $found >= 2' file.txt
Это решение достаточно лаконично и позволяет читать файл построчно, при этом Perl устанавливается по умолчанию на большинстве дистрибутивов Linux, что делает его доступным для большинства пользователей.
Альтернативный подход с использованием rg
(Ripgrep)
Если у вас установлен Ripgrep (rg)
, можно воспользоваться следующим решением:
third_occurrence_line=$(rg --max-count=3 --replace="" --line-number '^bingo.*$' input.txt | tail +3)
tail +"${third_occurrence_line%:}" input.txt
Это решение также поднимает вопрос о его эффективности, так как оно не исключает дважды просматривать файл: сначала с помощью rg
, а затем уже с помощью tail
.
Применение возможностей JavaScript
Для более современных решений можно использовать JavaScript, а именно библиотеку QuickJs. С помощью следующей команды вы можете также получить ожидаемый вывод:
qjs --std -e 'let [match, n] = scriptArgs.slice(-2); let re = new RegExp(match, "g"); let str = std.loadFile("test1.txt"); let res; let matches = 0; while ((res = re.exec(str)) !== null && ++matches != n) {if (matches === n) break;}; console.log(str.slice(res.index, str.length));' "bingo" 2
Заключение
Мы рассмотрели несколько способов, как распечатать файл, начиная с N-го вхождения строки "бинго". Каждое из предложенных решений имеет свои плюсы и минусы, в зависимости от используемых инструментов и сценариев использования. Выбор наиболее подходящего способа зависит от ваших потребностей и окружения, в котором вы работаете.