Подстановка строк в очень большой файл

10

У меня есть очень длинный ряд URL-адресов без разделительных символов, в том же формате, что и ниже:

http://example.comhttp://example.nethttp://example.orghttp://etc...

Я хочу, чтобы каждый URL был в новой строке. Я попытался сделать это, заменив все экземпляры "http: //" на "\ nhttp: //", используя sed

sed 's_http://_\nhttp://_g' urls.txt

но происходит ошибка сегментации (нарушение памяти). Я могу только предположить, что размер файла (более 100 ГБ) приводит к тому, что sed превышает некоторый предел.

Я мог бы разделить файл на несколько файлов меньшего размера для обработки, но все экземпляры "http: //" должны были бы быть сохранены.

Есть лучший способ это сделать?

С Сойер
источник
Я думаю, что sed не нравится 100 ГБ без окончаний строк, поскольку он пытается прочитать одну строку в своем буфере.
Джиппи
расщепление (независимо от того, «где» происходит разрез), обработка, затем повторная сборка должны, однако, дать правильный результат.
энзотиб
3
Если у вас действительно есть текстовый файл объемом 100 ГБ, содержащий одну длинную строку, то вам лучше написать быструю программу на Си для выполнения этой работы.
fpmurphy

Ответы:

11

С помощью awkвы можете избежать чтения огромного количества текста сразу:

awk -vRS='http://' -vORS='\nhttp://' 1 urls.txt > urlsperline.txt

Успех может зависеть от используемой awkреализации. Например gawkработает нормально, но mawkвылетает.

manatwork
источник
6

Это сделает работу:

perl -pe 'BEGIN { $/ = "//" } s!(?=http://\z)!\n!' urls.txt

Установив $ / , я изменил определение строки, чтобы она заканчивалась //вместо новой строки. Это заставляет Perl читать по одному URL за раз. Маловероятно, что URL-адрес содержит, //кроме как после схемы, но если все-таки все в порядке, регулярное выражение будет препятствовать добавлению ложных новых строк.

Если вы хотите не добавлять пустую строку перед первым URL:

perl -pe 'BEGIN { $/ = "//"; print scalar <> } s!(?=http://\z)!\n!' urls.txt

Вы можете попробовать сравнительный анализ, чтобы увидеть, s!http://\z!\nhttp://!быстрее ли . Они эквивалентны. Обратите внимание, что этот /gфлаг не требуется при замене, поскольку в каждой строке может быть только одно совпадение.

CJM
источник
Хорошо ли работает Perl regexp с линиями длиной в несколько гигабайт?
Алексиос
2
@Alexios, вероятно нет, но это не обязательно. Поскольку я изменился $/, он будет работать только с одним URL за раз.
CJM
Ах, я вижу, что ты там сделал. С 90-х годов прошло какое-то время, и мне пришлось man perlvar, но это имеет смысл.
Алексиос
Linux позволяет URL-адресам иметь несколько косых черт в путях, поэтому этот код может не работать, если у вас есть какой-либо из них. Тестирование всей строки, http и всего, не будет иметь этой проблемы.
Джо
@ Джо, я проверяю http:роль в регулярном выражении. Он будет проверять каждый //, но не будет добавлять новую строку, пока не найдет http://.
CJM
5
  1. Измените все вхождения :с новой строки, чтобы измельчить файл.
  2. замещать
    • http в конце строки с
    • перевод строки http:и добавление к ней следующей строки
  3. Повторите один раз, чтобы четные и нечетные строки обновлялись

Эти шаги выглядят так:

tr ':' '\n' | sed -e '/http$/{N;s/http\n/\nhttp:/}' | sed -e '/http$/{N;s/http\n/\nhttp:/}'
  1. Проверьте, есть ли строки, которые не начинаются с http://, напечатайте номера строк. Это может произойти, только если a: находится где-то в URL-адресе, кроме после http.

    grep -nv '^http://'

jippie
источник