Як вирізати частину файлу журналу?


18

У мене є файл журналу 8 Gb (журнал виробництва Rails). Мені потрібно розрізати його між деякими датами (рядками). Яку команду я можу використати для цього?


1
Ей, хлопці, це питання стосується великого файлу, тому це "Анте вгору!" .. Час має значення ... Я протестував вподобаний сценарій sed на реальному файлі 8 Гб, з 85904064 рядками (100 символів на рядок). Я люблю sed, але, як є, сценарій sed кожен раз сканує весь файл . Це робить його в середньому вдвічі повільніше, ніж awk-скрипт, який виходить, коли-коли знайдеться ... Я думаю, що (?) Сценарію sed може просто знадобитися aq замість d для другого виразу ... Результати тесту тут: вставити .ubuntu.com / 573477 .. Крім того, це не дає належного результату. Дивіться мій коментар наприкінці відповіді.
Пітер.O

Нова версія sed від asoundmove вирішила проблему швидкості, і тепер вона відповідає швидкості awks. а новий порівняно тепер виводить дані правильно ... див. його коментарі для більш детальної інформації.
Пітер.О

Я щойно помітив, що ви сказали "вирізати" (що зазвичай означає видалити) ... Ви дійсно маєте на увазі "вирізати", або ви маєте на увазі "копіювати"? .... Якщо ти мав на увазі "вирізати", то sedзробиш це легко.
Пітер.О

Відповіді:


12

Щось на зразок

sed '1,/last date prior to chunk/d;/first date after chunk/,$d' logfile | tee cut-log | less

tee cut-logдозволяє побачити на екрані, що вводиться у файл cut-log.

Редагувати:

Щоб задовольнити жорсткі стандарти fred.bear, ось рішення sed (хоча, мабуть, рішення awk набагато красуніше):

b=BB; e=EE ;echo -e "AA\nAA\nBB\nBB\nCC\nCC\nDD\nDD\nEE\nEE\nFF\nFF" | sed -n ":b;/$b/b p;n;b b;:p;p;n;/$e/b e;b p;:e;p;n;/$e/b e;q"


3
@dogbane: так, так. Відредаговано. Я впевнений, що ви іноді пишете менше оптимального коду, чи заслуговує він на такий різкий коментар?
asoundmove

1
Примітка: Якщо є кілька послідовних рядків "першого побачення" з однаковою датою, всі, крім перших, не будуть видалені, і вони будуть введені до виводу ... просто щось, про що слід знати ... (це залежить від ситуація)
Пітер.O

1
... але, хоча я про-sed ++, я вважаю, що ця робота виходить за її межі, інакше, ніж один власний особистий інструмент. Ось головне питання, яке має у цьому випадку sed (як ваш, і мій .. мені вдалося змусити sed зробити те саме, що і ваше .. він також запустився в межах 1%) .. повернутися до основної проблеми .. (що не стосується awk) .... помилка (не виправляється): Щодо дати, яка є дійсною в межах журналу, але насправді вона не присутня в журналі, у випадку 1-го аргументу не призведе до того, що sed нічого не надрукує, а у випадку 2-го arg, sed wil надрукує все після першого побачення! ... докладніше ...
Пітер.О

1
Ще одна, виправлена ​​помилка: чи відповідає вона наразі датам у будь-якому рядку, включаючи дані про дані, але це просто виправлення регексу. останні дати в діапазоні (не -1 і +1) .. і нарешті .. мої "вимогливі стандарти" не мої. Я тільки посланник запиту запитувачів ... Користувач буде помітити , якщо він працює в відповідно до проханням, чи ні .. Це був великий питання для мене .. Я дізнався багато :) ... і я радий , знати, що sedможе відповідати awkшвидкості, і це було насправді трохи швидше.
Пітер.О

6

Щоб надрукувати все між FOO та BAR включно, спробуйте:

$ sed -n '/FOO/,/BAR/p' file.txt

1
Примітка: Це надрукує лише перший BAR серії послідовних BARS ...
Peter.O

ще одна примітка ... Велика проблема, якщо жодна з дат відсутня в даних. Якщо останньої дати немає, sed буде зберігати рядки виводу, поки не досягне EOF.
Пітер.O

5

Це зробить те, що ви хочете ...
Відображаються дати включення та виключення параметрів.

# set Test args
set  2011-02-24  2011-02-26  "junk"

from="$1"
till="$2"
file="$3"

# EITHER ====                              +++++++++  
# Ouptut lines between two parameter dates INCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 >= from) && ($2 <= till) { print $0 ; next }
    ($2 > till) { exit }' "$file"

# OR ========                              ---------
# Ouptut lines between two parameter dates EXCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 > from) && ($2 < till) { print $0 ; next }
    ($2 >= till) { exit }' "$file"

Він перевіряє (відсортовану) дату в полі 2 ... Ось приклад даних тесту

    98  2011-02-05 xxxx
    99  2011-02-05 xxxx
   100  2011-02-06 xxxx
   101  2011-02-06 xxxx

А ось генератор тестових даних .


Я б написав це (взявши приклад першого) трохи простіше таким чином: awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove

@asoundmove: Так, це може виглядати краще, і це, безумовно, більш звичайно , але насправді час його виконання становить лише тривалість 1 додаткового ifтвердження загалом (навіть не 1 на рядок), тобто. логічний потік фактично однаковий, і різницю в часі виконання рахуватимуться в наносекундах ... Єдиною причиною, яку я не використовував "інше", є те, що це фактично мій перший в історії awkсценарій (окрім дня 4 років тому, коли я грав з деякими прикладами) ... і це перший працюючий механізм гілки, який я знайшов ... (і як уже згадувалося. це так само швидко) .. Я загалом використовую sedTryq
Peter.O

Я не розумію, де ви даєте ім'я та місце текстового файлу в цьому методі? може хтось допоможе мені побачити через мою дурість
Giles

4

Якщо у вашому файлі журналу є дати в такому форматі YYYY-MM-DD, то, щоб знайти всі записи для, скажімо, 2011-02-10, ви можете зробити:

grep 2011-02-10 log_file

Скажімо, якщо ви хочете знайти записи для 2011-02-10 та 2011-02-11, тоді знову використовуйте, grepале з кількома шаблонами:

grep -E '2011-02-10|2011-02-11' log_file

Добре. Він працює "як рекламується" :) ... Однак grepбуде шукати весь файл, навіть якщо діапазон дат знаходиться на початку файлу. В середньому це подвоює час пошуку в порівнянні з "вихід-після-останній-предмет-у-діапазоні" ... Мені це лише сподобається через розмір файлу в 8 Гб, згаданий у запитанні, результати греп-часу майже ідентичні прикладу sed (1 хв 58 сек). Ось посилання на результати моїх тестів за часом: paste.ubuntu.com/573477
Peter.O

1

Працювати з таким розміром файлів завжди важко.

Шлях вперед може бути розділити цей файл на пару маленьких, для цього можна скористатися командою split.

split -d -l 50000 ToBigFile.data file_

Навіть у вас це розділено, ви все одно можете працювати з файлом, як якщо б ви використовували bash для циклу

for f in `ls file_*`; do cat $f; done;

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

У цей момент ви просто працюватимете з великою кількістю менших файлів, а команди, згадані вище, працюватимуть більш бездоганно над багатьма меншими файлами.

І коли ви закінчите, ви можете використовувати секунду для циклу, щоб знову створити новий менший файл.

for f in `ls file_*`; do cat $f >> NewFile.data ; done;

Оновлення Оскільки ми починаємо розділяти дані на кілька файлів, з жорстким диском буде багато роботи, і це потребує часу. (У цьому питанні, мабуть, 5хв).

З іншого боку, наступні кроки, ймовірно, будуть швидшими.

Тож цей метод, ймовірно, безглуздий для простої роботи grep, awk, sed, але якщо шаблони пошуку ускладняться, вони можуть стати швидшими.


3
Йогаме, на пошук у файлі журналу 8 Гб на моєму комп’ютері в середньому потрібно лише 1 хвилину, а у того самого обчислювача, що розщеплює вхідний файл, потрібно 4 хвилини 43 сек ... :)
Peter.O

Скажімо, ви могли скоротити цей час у 50-відсотковий розмір на менших файлах. Тоді нам ще потрібно зробити більше 10 цих операцій, перш ніж ми отримаємо загальний час ... Тож, можливо, розділення файлів - не найкраща ідея для декількох регресій ...
Йохан,

Сценарій awk можна (легко) змінити, щоб вивести 10 різних результатів пошуку в 10 файлів ... за один прохід, але це сповільнить зчитування, фактично виводить звіти ... Sed також може зробити те саме, але як я Ви згадані в коментарях asoundmove, sed не вдасться, якщо конкретна дата / час не має запису в журналі (наприклад, ви шукаєте за годиною). Я багато використовую sed, і це надзвичайно корисно, але він має свої обмеження ... Ось питання про сед про те, коли використовувати sed vs awk .. Я не обов'язково з усім цим згоден, але я можу побачити, що вони означають ... sed.sourceforge.net/sedfaq6.html
Пітер. O

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