Заменить строку, содержащую новую строку в огромном файле

Заменить строку, содержащую новую строку в огромном файле

Кто-нибудь знает нестрочный инструмент для «бинарного» поиска/замены строк с более-менее эффективным использованием памяти способом?Видетьэтот вопросслишком.

У меня есть текстовый файл размером +2 ГБ, который я хотел бы обработать примерно так, как это выглядит:

sed -e 's/>\n/>/g'

Это значит, что я хочу удалить все переводы строк, которые встречаются после >, но не где-либо еще, так что это исключает tr -d.

Эта команда (которую я получил отответ на аналогичный вопрос) терпит неудачу с couldn't re-allocate memory:

sed --unbuffered ':a;N;$!ba;s/>\n/>/g'

Итак, есть ли другие методы, не прибегая к C? Я ненавижу Perl, но готов сделать исключение в этом случае :-)

Я не знаю наверняка ни одного символа, который не встречается в данных, поэтому \nя бы хотел по возможности избежать временной замены на другой символ.

Есть у кого-нибудь хорошие идеи?

решение1

В Perl это действительно тривиально, не стоит это ненавидеть!

perl -i.bak -pe 's/>\n/>/' file

Объяснение

  • -i: отредактируйте файл на месте и создайте резервную копию оригинала под названием file.bak. Если вам не нужна резервная копия, просто используйте perl -i -peвместо этого.
  • -pe: прочитать входной файл построчно и вывести каждую строку после применения скрипта, указанного как -e.
  • s/>\n/>/: замена, как и sed.

И вот awkподход:

awk  '{if(/>$/){printf "%s",$0}else{print}}' file2 

решение2

Решение perl:

$ perl -pe 's/(?<=>)\n//'

Объяснение

  • s///используется для замены строк.
  • (?<=>)это шаблон ретроспективного просмотра.
  • \nсоответствует новой строке.

Весь шаблон подразумевает удаление всех символов новой строки, которые были >до него.

решение3

Как насчет этого:

sed ':loop
  />$/ { N
    s/\n//
    b loop
  }' file

Для GNU sed вы также можете попробовать добавить опцию -u( --unbuffered) согласно вопросу. GNU sed также справляется с этим как с простой однострочной командой:

sed ':loop />$/ { N; s/\n//; b loop }' file

решение4

sedне предоставляет способа выдавать вывод без завершающего символа новой строки. Ваш подход с использованием Nв основном работает, но сохраняет неполные строки в памяти и, таким образом, может дать сбой, если строки станут слишком длинными (имплементации sed обычно не предназначены для обработки очень длинных строк).

Вместо этого вы можете использовать awk.

awk '{if (/<$/) printf "%s", $0; else print}'

Альтернативный подход заключается в использовании trдля замены символа новой строки на «скучный», часто встречающийся символ. Пробел может сработать здесь — выберите символ, который имеет тенденцию появляться в каждой строке или, по крайней мере, в большой части строк в ваших данных.

tr ' \n' '\n ' | sed 's/> />/g' | tr '\n ' ' \n'

Связанный контент