Показать полную графическую версию : Создание sql-скрипта для переноса txt в mysql
foxintel
16-03-2010, 20:46
Есть txt файл с логами, нужно его перенести в таблицу mysql. Вот пример лога:
03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"
А вот нужно его поместить в таблицу с колонками (date,time,user,ip,url,size,re,cache,pr,send,otv). Не могу разделить значения с "/". Возможно ли сделать это через sql или нужно дополнительно обрабатывать скриптом?
dmitryst
16-03-2010, 22:36
На perl:
$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split (' ', $stroka);
где $stroka это ваши
03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip" »
foxintel
16-03-2010, 23:07
А как сделать, что бы он читал из файла эти данные?
$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split (' ', $stroka); »
1)
Гм. это по моему просто разбиение строки находящейся в $stroka
разделенной пробелами и рассовывание результатов по скалярным переменным.
Т. к. оператор split всегда возвращает результат как массив, то здесь неявно используется массив по умолчанию @_
Т.е. результаты split присваиваются массиву, а затем элементы массива присваиваются отдельным скалярным переменным.
2)
В качестве зачачи пробела как разделителя, грамотнее использовать не ' ', а следующую конструкцию:
$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split /\s+/, $stroka;
3) Простейшее чтение из файла, где имя файла задается в параметрах вызова perl-программы выглядит так:
use strict;
while (<>) {
chomp; # удаление Enter, LF, и подобного
# print "Чо за $_"; Проверка считанного
$date,$time,$user,$ip,$url,$size,$re,$cache,$pr,$send,$otv = split /\s+/, $_;
# SQL вызов
}
# чтение происходит построчно, т. е. файл зараз целиком не считывается, что делает возможным обработку очень больших файлов
# Если имя обрабатываемого файла не указана (нет параметров вызова), то читается стандартный ввод, до Ctrl-Z - win, Ctrl-D - Unix
Так же нужно помнить, что элемент "200 OK gzip" содержит внутри себя пробелы.
Соответственно, нужно вводить более строгие правила, а не просто разбиение по пробельным символам
dmitryst
17-03-2010, 16:43
это по моему просто разбиение строки находящейся в $stroka »
да.
элемент "200 OK gzip" содержит внутри себя пробелы »
как я помню, можно просто (...) = split $stroka; , хотя проверить не на чем..
Код (используется ActivePerl 5.10.1)
#! c:\Perl\bin\perl.exe -w
use strict;
my $some_input="03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 \"200 OK gzip\"";
print "$some_input\n";
my @args=split/\s+/, $some_input;
foreach (@args) {
print "$_ \n";
}
print "---------------------------------------------------------\n";
Результат:
03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"
03.03.2010/19:03:21
fox/192.168.2.10
http://yandex.ru
7020
7020/493
100%
999
"200
OK
gzip"
---------------------------------------------------------
как я помню, можно просто (...) = split $stroka; »
Можно. Это просто короткая форма записи
(...) = split /\s+/,$stroka;
foxintel
17-03-2010, 21:17
да это все хорошо, но вот возможно ли еще \ поубирать? А то у меня и так данные в таблицу попадали
да это все хорошо, но вот возможно ли еще \ поубирать? А то у меня и так данные в таблицу попадали »
Не вопрос. Я могу набросать регулярное выражение которое разберет строку.
Только мне нужен пример разбора имеющейся строки такого плана
date,time,user,ip,url,size,re,cache,pr,send,otv
Имеем:
03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"
Надо:
date=03.03.2010
time=19:03:21
user=fox
ip=192.168.2.10
url=http://yandex.ru
и так до
otv=
2)
Пример соединения с mySQL я приведу попозжа
dmitryst
17-03-2010, 23:01
используется ActivePerl 5.10.1 »
а почему на перле? Я-то кроме него ничего не знаю, просто предложил как вариант :)
а почему на перле? Я-то кроме него ничего не знаю, просто предложил как вариант »
Потому что,
1) это единственный язык где регулярные выражения родные, а не прикручены при помощи классов, как в C# - например.
2) Perl создан как обработчик лог-файлов и это он делает гораздо лучше остальных
3) Решил потренироваться, давно не брал в руки шашку :)
=================================
Использование модуля DBI
#! c:\Perl\bin\perl.exe -w
use DBI;
# Заменить dbname, mysqlserver.domain.com, db_username, password на реальные данные
$dbh=DBI->connect('DBI:mysql:dbname:mysqlserver.domain.com:3306', 'db_username', 'password', {RaiseError=>1}) or die "connecting : $DBI::errstr\n";
# 03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 "200 OK gzip"
# date,time,user,ip,url,size,re,cache,pr,send,otv
# Предполагаем , что переменные уже присвоены
$date='03.03.2010';
$time='19:03:21';
$user='fox';
$ip='192.168.2.10';
$url='http://yandex.ru';
$size=7020;
$re=7020;
$cache=493;
$pr='100%';
$send='999';
$otv='200 OK gzip';
# Конверсии printf
# %g - число
# %d - десятичное целое
# %s строка
# %f - число с плавающей запятой
# Подготовка строки -шаблона SQL оператора
my $sql_fmt= "INSERT INTO tablename VALUES(%s, %s, %s, %s, %s, %d, %d, %d, %s, %d, %s)";
# Формирование SQL-запроса, column_name заменить на реальные имена столбцов
my $sql=sprintf($sql_fmt, $date->column_name, $time->column_name, $user->column_name, $ip->column_name, $url->column_name, $size->column_name, $re->column_name, $cache->column_name , $pr->column_name, $send->column_name, $otv->column_name);
# вызов
$dbh->do ($sql);
$dbh->disconnect;
Разложение строки при помощи регулярных выражений в Perl
#! d:\Perl\bin\perl.exe -w
#use strict;
my $some_input="03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 \"200 OK gzip\"";
# date,time,user,ip,url,size,re,cache,pr,send,otv
chomp $some_input;
print "$some_input\n";
print "begin---------------------------------------------------------\n";
$some_input =~ m{^([0-9]{1,2}.[0-9]{1,2}.[0-9]{2,4})/([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})\b \b(\w+)/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\b \b(\S+)\b \b(\d+)\b \b(\d+)/(\d+)\b \b(\d+)% \b(\d+)\b (.*)$};
my $date=$1;
my $time=$2;
my $user=$3;
my $ip=$4;
my $url=$5;
my $size=$6;
my $re=$7;
my $cache=$8;
my $pr=$9;
my $send=$10;
my $otv=$11;
print " $date\n $time\n $user\n $ip\n $url\n $size\n $re\n $cache\n $pr\n $send\n $otv\n";
print "end---------------------------------------------------------\n";
Кстати. Хозяйке на заметку :)
Обрабатываемый файл, как я понимаю, представляет собой один из форматов формат apach
В таком формате данные отдает: SQUID и Apach в режиме акселератора.
Так как сервер может покоцать код, добавляю как файл
dmitryst
19-03-2010, 22:14
kim-aa, браво!
1) это единственный язык где регулярные выражения родные, а не прикручены при помощи классов, как в C# - например.
2) Perl создан как обработчик лог-файлов и это он делает гораздо лучше остальных »
согласен на 100%, но надо бы спросить автора темы, может, у него нет возможности на перле скрипты запускать ;)
В таком формате данные отдает: SQUID »
там еще есть данные по попаданию/не попаданию в кэш, и еще по мелочи.
foxintel
19-03-2010, 22:25
Сейчас бы еще разобраться, как его запустить. Не ругайтесь сильно, но я не знаю как это. У меня есть перл + у меня Windows
1) Скачиваете ActivePerl
2) Скачиваете Notepad++ из приложенного архива, им удобно просматривать код
предварительно выбрав Language\Perl
3) Инсталируете ActivePerl
4) Распаковываете Notepad
5) Скачиваете полученный код и переименовываете его в ro-0.pl и кладете ну скажем в корень D:\
6) Запускаете CMD
7) D:\
8) perl ro-0.pl
Очень помагает наличие FAR или TotalCMD
Вариант, возможно более наглядный для новичка.
Сначала производятся замены на Tab как разделитель столбцов.
Потом полученная строка разбирается Split
#! d:\Perl\bin\perl.exe -w
use strict;
my $some_input="03.03.2010/19:03:21 fox/192.168.2.10 http://yandex.ru 7020 7020/493 100% 999 \"200 OK gzip\"";
print "$some_input\n";
#Замена "/ цифра" на "/Tab"
$_=$some_input;
s{/(\d)}{\t$1}g;
my $tmp=$_;
#Замена ":21 fox" на ":21(Tab)fox"
$_=$tmp;
s{(:\d\d) (\w)}{$1\t$2};
$tmp=$_;
#Замена ".xxx http" на ".xxx(Tab)http"
$_=$tmp;
s{(.\d{1,3}) (\w)}{$1\t$2};
$tmp=$_;
#Замена ".ru 7020" на ".ru(Tab)7020"
$_=$tmp;
s{(\S) (\d)}{$1\t$2};
$tmp=$_;
#Замена "7020 7020" на "7020(Tab)7020"
$_=$tmp;
s{(\d) (\d)}{$1\t$2};
$tmp=$_;
#Замена "493 100%" на "493(Tab)100%"
$_=$tmp;
s{(\d) (\d+%)}{$1\t$2};
$tmp=$_;
#Замена "100% 999" на "100%(Tab)999"
$_=$tmp;
s{(\d+%) (\d)}{$1\t$2};
$tmp=$_;
#Замена "999 \" на "999(Tab)\"
$_=$tmp;
s{(\d) }{$1\t};
$tmp=$_;
print "$tmp\n";
my @args=split/\t/, $tmp;
print "begin---------------------------------------------------------\n";
foreach (@args) {
print "$_ \n";
}
print "end---------------------------------------------------------\n";
foxintel
29-03-2010, 18:06
kim-aa Большое спасибо за код. Но как прописать, что бы исходные данне он брал из текстового файла?
foxintel,
Файлик приведите, я на нем и попробую.
И приведу образец кода.
ЗЫ. Будущий урок будет называться дескрипторы в Perl :)
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.
Available in ZeroNet 1osznRoVratMCN3bFoFpR2pSV5c9z6sTC