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