Підстановка рядків у дуже великий файл


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 Гб без закінчень рядків, оскільки він намагається прочитати один рядок у своєму буфері.
джиппі

розщеплення (незалежно від того, "де" відбувається розріз), обробка, потім повторна збірка повинна дати проте правильний результат.
enzotib

3
Якщо у вас справді є текстовий файл розміром 100 Гб, що містить один довгий рядок, тоді вам краще написати швидку програму C, щоб виконати роботу.
fpmurphy

Відповіді:


11

Завдяки цьому awkви можете уникнути читання величезної кількості тексту одночасно:

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

Успіх може залежати від використовуваної awkреалізації. Наприклад, gawkпрацює добре, але mawkвиходить з ладу.


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прапор не потрібен для заміни, оскільки на "рядок" може бути лише одна відповідність.


Чи гаразд двигун perge regexp добре з багатогігабайтними лініями?
Олексій

2
@ Алексіос, напевно, ні, але цього не потрібно. Оскільки я змінився $/, він матиме справу лише з однією URL-адресою.
cjm

А, я бачу, що ти там робив. Минув час з 90-х, і мені довелося man perlvar, але це має сенс.
Олексій

Linux дозволяє URL-адресам вбудовувати декілька косої риски в контури, тому цей код може вийти з ладу, якщо у вас є будь-який з них. Тестування для всього рядка, http та всього цього проблеми не матиме.
Джо

@Joe, я тестую на 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://'

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.