Intereting Posts
SSH на сервер, используя билет обслуживания kerberos, который не является основным хозяином Как расширить раздел на все нераспределенное пространство в VPS? Поиск файла на основе диапазона данных Перемещение / загрузка раздела без испорчения системы Локальный кеш Nix игнорируется, поскольку в файле информации NAR отсутствует подпись В Linux «топ» команда: какие мы, sy, ni, id, wa, hi, si и st (для использования ЦП)? sudo: нет tty присутствует и не указана программа прохода не может заставить «awk for loop» работать, используя basename Для `tint2`, как вы настраиваете панель задач, чтобы всегда показывать, на каком рабочем пространстве вы находитесь? Почему большинство обычных менеджеров пакетов Linux не позволяют устанавливать пакет для обычных пользователей? Как извлечь корневой ЦС и подчиненный ЦС из цепочки сертификатов в Linux? Есть ли способ поделиться службой, прослушивающей петлю хоста с гостем LXC? Что такое $ () в команде? получить IP-адрес, который изменил файл Настройте среду для кросс-компиляции на i386, armel, armhf, arm64 и mips без конфликтов libglib2

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

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

У меня есть текстовый файл + 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 другим символом – это то, что я хотел бы избежать, если это возможно.

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

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