Как вырезать часть из файла журнала?

18

У меня есть файл журнала 8 Гб (журнал производства Rails). Мне нужно сократить это между некоторыми датами (линиями). Какую команду я могу использовать для этого?

Эрик Лещинский
источник
1
Эй, ребята, этот вопрос касается большого файла, так что это «Ante up!» ... время имеет значение ... Я проверил любимый скрипт sed на реальном файле 8 ГБ, с 85904064 строками (100 символов в строке). Я люблю sed, но в настоящее время сценарий sed сканирует весь файл каждый раз. Это делает его в среднем вдвое медленнее, чем скрипт awk, который завершается при обнаружении ... Я думаю (?) Сценарию sed может понадобиться просто aq вместо d для второго выражения ... Результаты теста здесь: paste .ubuntu.com / 573477 .. Кроме того, он не дает правильного вывода .. см. мой комментарий в конце ответа asoundmove.
Peter.O
Новая версия sed asoundmove решает проблему скорости, и теперь она соответствует скорости awks. и новый версин теперь выводит данные правильно ... см. его комментарии для более подробной информации.
Peter.O
Я только что заметил, что вы сказали «вырезать» (что обычно означает «удалить») ... Вы действительно имеете в виду «вырезать» или «копировать»? .... Если вы имели в виду «вырезать», то sedсделаем это легко.
Peter.O

Ответы:

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"
asoundmove
источник
-1 UUOC partmaps.org/era/unix/award.html
собачья будка
3
@ Dogbane: да, да. Ред. Я уверен, что вы иногда пишете неоптимальный код, заслуживает ли он такого резкого комментария?
asoundmove
1
примечание: если есть несколько последовательных строк «первой даты» с одной и той же датой, все, кроме первой, не будут удалены, и будут представлены в выводе ... просто что-то, что нужно знать ... (это зависит от ситуация)
Peter.O
1
... но, несмотря на то, что я pro-sed ++, я думаю, что эта конкретная работа выходит за ее пределы, для чего-либо, кроме одного «личного инструмента». Вот основная проблема, которую sed имеет в этом случае (ваш, и мой .. мне удалось заставить sed сделать то же самое, что и твой .. он также работал в пределах 1%) .. вернуться к основной проблеме .. (что не относится к awk) .... ошибка (не устраняется): Что касается даты, которая является действительной в рамках журнала, но фактически не присутствует в журнале, то в случае с 1-м аргументом sed ничего не печатает, а в случае 2-го аргумента sed будет печатать все после первого свидания! ... подробнее ...
Peter.O
1
Еще одна исправимая ошибка: в настоящее время она совпадает с датами, где бы они ни находились в любой строке, включая представление данных, но это всего лишь подстройка регулярного выражения. И для любого, кто хочет его использовать, возможно, вы могли бы прокомментировать, что аргументы теперь относятся к первому и последние даты в диапазоне (не -1 и +1) .. и наконец .. мои "строгие стандарты" не мои. Я только посланник запроса спрашивающих ... Пользователь будет заметить , если он работает в соответствии с просьбой, или нет .. Это был большой вопрос для меня .. Я узнал много :) ... и я рад , знать, что sedможет соответствовать awkскорости, и это было на самом деле немного быстрее.
Peter.O
6

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

$ sed -n '/FOO/,/BAR/p' file.txt
кендырь
источник
1
примечание: это будет печатать только первый BAR серии последовательных BARS ...
Peter.O
еще одно замечание ... Большая проблема, если одна из дат не присутствует в данных. Если последняя дата не указана, sed будет продолжать выводить строки, пока не достигнет EOF.
Peter.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

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

Peter.O
источник
Я бы написал это (например, первый) чуть проще: awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove
@asoundmove: Да, это может выглядеть лучше, и это определенно более условно , но на самом деле время его выполнения составляет всего лишь 1 дополнительный ifоператор в общей сложности (даже не 1 на строку), т.е. логический поток фактически такой же, и разница во времени выполнения будет подсчитываться в наносекундах .... Единственная причина, по которой я не использовал "else", заключается в том, что это фактически мой первый awkсценарий (за исключением одного дня 4 года). назад, когда я играл с некоторыми примерами) ... и это первый работающий механизм ветвления, который я нашел ... (и, как уже упоминалось, он так же быстр) .. Я обычно использую sedTryq
Peter.O
Я не понимаю, где вы даете имя текстового файла и местоположение в этом методе? может ли кто-нибудь помочь мне увидеть мою глупость
Джайлс
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будет искать весь файл, даже если диапазон дат находится в начале файла. В среднем это удваивает время поиска, по сравнению с «exit-after-last-item-in-range» ... Я только затрудняюсь упомянуть это из-за размера файла 8 ГБ, упомянутого в вопросе, Ваш Результаты grep time практически идентичны приведенному здесь примеру sed (1 мин 58 с). Вот ссылка на мои результаты тестов времени: paste.ubuntu.com/573477
Peter.O
1

Работать с файлами такого размера всегда сложно.

Путь вперед может состоять в том, чтобы разбить этот файл на пару маленьких, для этого вы можете использовать команду split.

split -d -l 50000 ToBigFile.data file_

Даже если он разделен, вы все равно можете работать с файлом, как если бы он использовал цикл bash for

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

Но вместо кошки вы можете использовать инвертированный grep, чтобы избавиться от нежелательных данных, что для этого не имеет значения. (или вид уточнения, который вам нужен).

На этом этапе вы будете просто работать с большим количеством файлов меньшего размера, а команды, упомянутые выше, будут работать с большим количеством файлов меньшего размера.

И когда вы закончите, вы можете использовать второй цикл for, чтобы снова создать новый файл меньшего размера.

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

Обновление Поскольку мы начинаем разделять данные на несколько файлов, с жестким диском будет много работы, и это займет время. (В этом вопросе видимо 5мин).

С другой стороны, следующие шаги, вероятно, будут быстрее.

Так что этот метод, вероятно, не имеет смысла для простых операций grep, awk, sed, но если шаблоны поиска станут более сложными, они могут стать быстрее.

Johan
источник
3
Йохан, для поиска 8-гигабайтного файла журнала на моем компьютере в среднем требуется всего 1 минута, а на том же компьютере только начальное разбиение файла занимает 4 минуты 43 секунды ... :)
Peter.O
Допустим, вы можете сократить эти awk и sed времена на 50% для небольших файлов. Затем нам нужно выполнить более 10 таких операций, прежде чем мы выиграем общее время ... Так что, возможно, разделение файлов - не лучшая идея для нескольких регрессий ...
Йохан
Скрипт awk можно (легко) изменить, чтобы выводить 10 разных результатов поиска в 10 файлов ... за один проход, но это замедляло бы чтение при выводе отчетов ... Sed мог бы делать то же самое, но, как я Как уже упоминалось в комментариях asoundmove, sed не будет работать, если у конкретной даты / времени нет записи в журнале (например, вы ищете по часам). Я часто использую sed, и это чрезвычайно полезно, но у него есть свои ограничения. ... Вот FAQ по sed о том, когда использовать sed против awk .. Я не обязательно согласен со всем этим, но я могу понять, что они означают ... sed.sourceforge.net/sedfaq6.html
Питер. О
0
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file
charlesbridge
источник
Это будет печатать только первую запись журнала за 2011-02-25, хотя.
Жиль "ТАК - перестань быть злым"