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

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

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

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

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

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

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

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

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

Любые хорошие идеи, кто-нибудь?

  • Редактирование вложенного текста и определенных строк в файле с использованием сценария bash
  • Отменить перемещение букв с помощью sed
  • Как удалить все пробелы между скобками с помощью bash?
  • Использование sed для преобразования строк в строки
  • Легко получить конкретный столбец из вывода без sed или awk
  • Как добавить новые строки из другого файла с помощью sed
  • sed удалить все, кроме первой и последней строки из многих файлов
  • Разбор таблицы текстовых файлов и агрегирование информации
  • 8 Solutions collect form web for “Заменить строку, содержащую новую строку в огромном файле”

    Это действительно тривиально в 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 

    Решение perl :

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

    Explaination

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

    Все значения шаблона удаляют всю новую строку, которая имеет > перед ней.

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

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

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

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

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

     sed ':a;$!N;s/>\n/>/;P;D;ba' 

    РЕДАКТИРОВАТЬ: после перечитывания знаменитых одноразовых песен Питера Круминьса, я считаю, что лучшее решение sed будет

     sed -e :a -e '/>$/N; s/\n//; ta' 

    который добавляет следующую строку только в том случае, если в конце он уже сделал > совпадение, и должен условно вернуться назад, чтобы обработать случай последовательных совпадающих строк (это 39% Крюмина). Добавьте строку к следующей, если она заканчивается обратная косая черта «\» точно, за исключением замены символа > для \ в качестве символа объединения, и того факта, что символ соединения сохраняется на выходе).

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

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

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

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

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

    как насчет использования ed?

     ed -s test.txt <<< $'/fruits/s/apple/banana/g\nw' 

    (через http://wiki.bash-hackers.org/howto/edit-ed )

    Я закончил использование gsar, как описано в этом ответе следующим образом:

     gsar -F '-s>:x0A' '-r>' 

    Есть много способов сделать это, и большинство из них действительно хороши, но я думаю, что это мой любимый:

     tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/' 

    Или даже:

     tr '>\n' '\n>' | sed 's/^>*//' | tr '\n>' '>\n' 
    Linux и Unix - лучшая ОС в мире.