Расщепление лог-файл на более мелкие файлы


У меня был файл, который выглядел так:

Mar 06 22:00:00 [10.251.132.246] logger: 10.64.69.219 - - [06/Mar/2011:22:.....
Mar 06 22:00:00 [10.251.132.246] logger: 10.98.137.116 - - [06/Mar/2011:22:0....

что я хотел разбить на файлы меньшего размера с помощью IP-адреса после "логгер"

Вот что я придумал:

file = ARGV.shift
split_file = {}
pattern = /logger: ([^\s]*)/
File.open(file, 'r') do |f|
    f.each do |l|
        match = l[pattern]
        if match
            list = split_file[$1]
            list = [] if list == nil
            list << l
            split_file[$1] = list
        end
    end
end

split_file.each_pair do |k, v|
    File.open("#{file}.#{k}", "a+") do |f|
        v.each do |l|
            f.print l
        end
    end
end

Предложения, предупреждения, улучшения приветствуются :)

Одна вещь, которую я заметил, состоит в том, что новые файлы создаются в той же директории, что и исходный файл, а не в текущей рабочей директории (так ./logsplitter.РБ ../журнала.журнал создает файлы в каталог..).

Спасибо

[правка: опечатка]



674
6
задан 8 марта 2011 в 07:03 Источник Поделиться
Комментарии
1 ответ

В первую очередь это довольно широко распространено конвенции в Ruby использовать 2 места для indendation не 4. Лично меня не волнует, но есть некоторые разработчики на Ruby, которые будут жаловаться, когда вижу код с отступом в 4 пробела, так что вы будете иметь более легкое время, просто иду с потоком.


file = ARGV.shift

Если есть хорошая причина, чтобы мутировать АГДУ (который в данном случае не похоже), я бы рекомендовал не использовать мутирующие операции. файл = из argv[0] будет отлично работать здесь.


match = l[pattern]
if match
list = split_file[$1]
list = [] if list == nil
list << l
split_file[$1] = list
end

Прежде всего, вы должны избегать использования магических переменных. Используя объекты MatchData является более надежной, чем использование магических переменных. В качестве примера рассмотрим такой сценарий:

Предположим, что вы решили, что хотите сделать некоторые обработки на линии, прежде чем хранить его в split_file. Для этого вы решите использовать gsub. Теперь ваш код выглядит так:

match = l[pattern]
if match
list = split_file[$1]
list = [] if list == nil
list << l.gsub( /some_regex/, "some replacement")
split_file[$1] = list
end

Однако этот код сломан. С gsub также устанавливает $1, $1 теперь не содержит, что вы думаете он делает и split_file[$1] не работает, как ожидалось. Такого рода ошибка не может произойти, если вы используете [1] на соответствие объекта данных вместо.

Далее, весь код может быть упрощен с помощью очень полезной особенностью Руби хэш: блоки по умолчанию. Хэши в Ruby позволяет указать блок, который выполняется, когда ключ не найден. Таким образом, вы можете создать хэш-массивы, которые вы можете просто добавить без того, чтобы убедиться, что массив существует.

Для этого нужно изменить инициализации split_file от split_file = {} , чтобы split_file = хэш.новый {|сек к| сек[к] = [] }. Затем вы можете заменить приведенный выше код с:

match = l.match(pattern)
if match
split_file[ match[1] ] << l
end



Одна вещь, которую я заметил, состоит в том, что новые файлы создаются в той же директории, что и исходный файл, а не в текущей рабочей директории (так ./logsplitter.РБ ../журнала.журнал создает файлы в каталог..).

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

File.open("#{ File.basename(file) }.#{k}", "a+") do |f|

Говоря об этой линии: я не понимаю, почему вы используйте "+" вместо "а" в качестве режима открытия - вы никогда не читали из нее.

4
ответ дан 8 марта 2011 в 03:03 Источник Поделиться