Как я могу обрезать файл (хороший входной поток), чтобы получить только строки в диапазоне от первого вхождения шаблона foo
до последнего вхождения шаблона bar
?
Например, рассмотрим следующий вход:
A line
like
foo
this
foo
bar
something
something else
foo
bar
and
the
rest
Я ожидаю этот вывод:
foo
this
foo
bar
something
something else
foo
bar
text-processing
sed
rahmu
источник
источник
foo
и последнееbar
и распечатаете все между ними, если что-нибудь. С потоком вам придется читать до первойfoo
и буферизовать все последующие строки в памяти до EOF, очищая буфер каждый раз, когдаbar
просматривается a . Это может означать буферизацию всего потока в памяти.Ответы:
Соответствие шаблону sed
/first/,/second/
читает строки одну за другой. Когда какая-либо строка соответствует/first/
ей, она запоминает ее и ожидает первого совпадения для/second/
шаблона. В то же время применяются все действия, указанные для этого шаблона. После этого процесс начинается снова и снова до конца файла.Это не то, что нам нужно. Нам нужно посмотреть до последнего соответствия
/second/
шаблона. Поэтому мы строим конструкцию, которая выглядит только для первой записи/foo/
. Когда найдено, циклa
начинается. Мы добавляем новую строку в буфер совпаденийN
и проверяем, соответствует ли она шаблону/bar/
. Если это произойдет, мы просто распечатаем его и очистим буфер совпадений и переместимся в начало цикла с помощьюba
.Также нам нужно удалить символ новой строки после очистки буфера с помощью
/^\n/s/^\n//
. Я уверен, что есть намного лучшее решение, к сожалению, оно не пришло мне в голову.Надеюсь, все ясно.
источник
sed
версиях, например, BSD sed (что и есть на Mac), за тегами должен следовать символ новой строки или конца строки, поэтому необходима следующая настройка:sed -n -e '/foo/{:a' -e 'N;/^\n/s/^\n//;/bar/{p;s/.*//;};ba' -e '};'
это также работает в GNU sed, поэтому я думаю, что это изменение (несколько-e
аргументов) окончание аргумента после каждого имени ветки) - хорошая переносимая привычка при использовании ветвей в sed.Я бы сделал это с небольшим Perl однострочником.
доходность
источник
E
вместоe
и-00777
вместо$/
бита (см. Perlrun (1)). Что бы сократить его до:,perl -0777 -nE 'say /(foo.*bar)/s'
все еще вроде читабельным.-0[octal]
найдет свой путь в моем рабочем процессе! Спасибо за этоВот двухпроходное решение GNU sed, которое не требует большого количества памяти:
объяснение
sed
вызов проходит infile и находит первое вхождениеfoo
и все последующие вхожденияbar
.sed
скрипт с двумя вызовамиsed
и однимtr
. Выход третийsed
есть[start_address],[end_address]p
, без скобок.sed
проходитinfile
, печатая найденные адреса и все, что между ними.источник
Если входной файл удобно помещается в памяти, сделайте это просто .
Если входной файл огромен, вы можете использовать
csplit
его сначала для разбиения на части,foo
аbar
затем для каждой последующей сборки. Куски называетсяpiece-000000000
,piece-000000001
и т.д. Выберите префикс (здесьpiece-
) , что не конфликтует с другими существующими файлами.(В системах, отличных от Linux, вам придется использовать большое количество внутри фигурных скобок, например
{999999999}
, и пропустить-k
опцию. Это число - количествоbar
штук.)Вы можете собрать все части с
cat piece-*
, но это даст вам все после первогоfoo
. Так что сначала удалите этот последний кусок. Так как имена файлов, создаваемые с помощьюcsplit
, не содержат никаких специальных символов, вы можете работать с ними без каких-либо особых мер предосторожности, например сили эквивалентно
Теперь вы можете объединить все части и удалить временные файлы:
Если вы хотите удалить части по мере их объединения для экономии места на диске, сделайте это в цикле:
источник
Вот еще один способ с
sed
:Он добавляет каждую строку в
/foo/,$
диапазоне (строки,!
не входящие в этот диапазон,d
выбираются) вH
старое пространство. Линии, которые не совпадаютbar
, затем удаляются. На совпадающих строках пространство образца освобождается, ex
изменяется с пространством удержания, а ведущая пустая строка в пространстве образца удаляется.При огромных входных данных и небольшом числе случаев
bar
это должно быть (намного) быстрее, чем вытягивать каждую строку в пространство шаблона, а затем каждый раз проверять пространство шаблонаbar
.Разъяснение:
Конечно, если это файл (и помещается в памяти), вы можете просто запустить:
потому что
ed
можно искать вперед и назад.Вы даже можете прочитать вывод команды в текстовый буфер, если ваша оболочка поддерживает подстановку процесса:
или, если это не так, с помощью
gnu ed
:источник
Использование любого awk в любой оболочке в любой системе UNIX и без чтения всего файла или входного потока в память одновременно:
источник
Grep также может это сделать (ну, GNU grep):
Для ввода из тела вопроса:
источник