Кто-нибудь знает о нестрочном инструменте для «двоичного» поиска / замены строк в несколько эффективном для памяти режиме? См. Также этот вопрос .
У меня есть текстовый файл + 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'
Я закончил использование 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'