Кто-нибудь знает инструмент, не основанный на строках, для «бинарного» поиска / замены строк в некотором смысле эффективным способом памяти? Смотрите и этот вопрос .
У меня есть текстовый файл + 2 ГБ, который я хотел бы обработать аналогично тому, как это выглядит:
sed -e 's/>\n/>/g'
Это означает, что я хочу удалить все новые строки, которые появляются после >
, но нигде больше, так что это исключает tr -d
.
Эта команда (которую я получил из ответа на аналогичный вопрос ) не выполняется с couldn't re-allocate memory
:
sed --unbuffered ':a;N;$!ba;s/>\n/>/g'
Итак, есть ли другие методы, не прибегая к C? Я ненавижу Perl, но готов сделать исключение в этом случае :-)
Я точно не знаю ни одного символа, который не встречается в данных, поэтому временную замену \n
другим символом я бы хотел избежать, если это возможно.
Любые хорошие идеи, кто-нибудь?
источник
--unbuffered
?--unbuffered
памятью или без$!
?$!
хотя я не знаю, что это такое. Это Я ожидаю , что потребуется МНОГО памяти.sed
это не правильный инструмент в этом случае.Ответы:
Это действительно тривиально в Perl, вы не должны ненавидеть это!
объяснение
-i
: отредактируйте файл на месте и создайте резервную копию оригиналаfile.bak
. Если вы не хотите резервное копирование, просто используйтеperl -i -pe
вместо этого.-pe
: читать входной файл построчно и печатать каждую строку после применения скрипта, заданного как-e
.s/>\n/>/
: замена, просто какsed
.И вот
awk
подход:источник
awk '{ORS=/>$/?"":"\n"}1'
':a;N;$!ba;s/>\n/>/g'
в свой вопрос это чудовище , вы отказались от права жаловаться на удобочитаемость! : Pfoo ? bar : baz
конструктом, но не смог заставить его работать.perl
Решение:Explaination
s///
используется для подстановки строк.(?<=>)
это шаблон\n
соответствует новой строке.Весь шаблон означает удаление всех символов новой строки, находящихся
>
перед ним.источник
s/>\n/>/
?s/>\K\n//
также будет работатьКак насчет этого:
Для GNU sed вы также можете попробовать добавить опцию
-u
(--unbuffered
) в соответствии с вопросом. GNU sed также доволен этим как простой однострочник:источник
\n
если файл заканчивается>\n
, но это, вероятно, предпочтительнее в любом случае.}
должно быть в отдельном выражении? это не будет работать как многострочное выражение?b loop\n}
или ,-e 'b loop' -e '}'
но не такb loop;}
и , конечно , не так ,b loop}
потому что}
и;
действительны в именах меток (хотя никто в здравом уме не будет использовать. А это означает , что GNU SED не POSIX совместимый) и}
потребность команды должны быть разделено изb
команды.sed
доволен всем вышеперечисленным, даже с--posix
! Стандарт также имеет следующие выражения для скобок -The list of sed functions shall be surrounded by braces and separated by <newline>s
. Не означает ли это, что точки с запятой следует использовать только за скобками?>
. У оригинала никогда не было такового, на это указал Стефан.Вы должны быть в состоянии использовать
sed
сN
командой, но хитрость будет состоять в том, чтобы удалять одну строку из пространства образца каждый раз, когда вы добавляете другую (так, чтобы пространство образца всегда содержало только 2 последовательные строки, вместо того, чтобы пытаться читать полностью). файл) - попробуйРЕДАКТИРОВАТЬ: после перечитывания объяснения знаменитых Sed One-Liners Петерис Круминьш я думаю, что лучшее
sed
решение будеткоторый добавляет только следующую строку в том случае, если
>
в конце уже выполнено совпадение, и должен условно вернуться назад, чтобы обработать случай последовательных совпадающих строк (это 39 Крумина. Добавить строку к следующей, если она заканчивается обратной косой чертой «\» именно для замещения исключением>
для\
как присоединиться характер, и тот факт , что присоединиться символ сохраняется на выходе).источник
>
(это также специфично для GNU)sed
не обеспечивает способ вывода вывода без окончательного перевода строки. Ваш подход, основанный на использовании, вN
основном работает, но хранит неполные строки в памяти и, следовательно, может потерпеть неудачу, если строки становятся слишком длинными (внедрения sed обычно не предназначены для обработки очень длинных строк).Вместо этого вы можете использовать awk.
Альтернативный подход - использовать
tr
для замены символа новой строки «скучный», часто встречающийся символ. Здесь может сработать пробел - выберите символ, который имеет тенденцию появляться в каждой строке или, по крайней мере, в значительной части строк в ваших данных.источник
sed
не работает без буфера 2,5 ГБ.tr
подход - mikeserv, вы опубликовали другой (действительный, но менее общий) подход, который также используетсяtr
.что насчет использования ed?
(через http://wiki.bash-hackers.org/howto/edit-ed )
источник
В итоге я использовал gsar, как описано в этом ответе, вот так:
источник
Есть много способов сделать это, и большинство из них действительно хороши, но я думаю, что это мой любимый:
Или даже:
источник
*
. Теперь он удалит все пустые строки, следующие за строкой, заканчивающейся на>
. ... хм. Оглядываясь назад на вопрос, я вижу, что это немного неоднозначно. Вопрос говорит: «Я хочу , чтобы удалить все переводы строк , которые происходят после того, как>
...» Я расцениваю , что означает , что>\n\n\n\n\nfoo
должно быть изменено\n\n\n\nfoo
, но я полагаю ,foo
может быть желаемым результатом.printf '>\n>\n\n>>\n>\n>>>\n>\nf\n\nff\n>\n' | tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'
- это дает>>>>>>>>>>f\n\nff\n\n
мне первый ответ. Мне любопытно, что вы делаете, чтобы сломать это, потому что я хотел бы это исправить. Что касается второго пункта - я не согласен, что это неоднозначно. OP не просит , чтобы удалить все>
предшествующие на\n
ewline, но вместо того, чтобы удалить все\n
ewlines следующего>
.>\n\n\n\n\n
только после первого символа новой строки следует после>
; все остальные следуют другим переводам. Обратите внимание, что предложение ОП «это то, что я хочу, если бы это сработало»sed -e 's/>\n/>/g'
, не былоsed -e 's/>\n*/>/g'
.s/>\n/>/
по ->\n\n\n\n\n
прежнему будет то , чтоs/>\n/>/
будет править.