Страница 1 из 1

Подскажите с tr

Добавлено: 2011-05-03 10:36:15
kharkov_max
Добрый день.

Есть лог файл который необходимо обработать соотвествующим образом.
В логе есть нечто такое:

Код: Выделить всё

"слово1\слово2"
Необходимо преобразовать в

Код: Выделить всё

"слово1","слово2"
Т.е. по сути символ \ заменить на сочетание символов ",".
Погуглив нашел что это может сделать tr но кавычки "" это вроде как спецсимвол и сделать замену на такое сочетание символов не получается.
Подскажите пожалуйста как правильно сделать такое преобразование ?

Пробовал делать так:

Код: Выделить всё

tr \ \"\,\" 
В результате получаю так "слово1"слово2" - что меня не устраивает ...

Заранее спасибо за помощь.

Re: Подскажите с tr

Добавлено: 2011-05-03 11:31:48
rmn

Код: Выделить всё

awk -F\\ '{print $1"\",\""$2}'

Re: Подскажите с tr

Добавлено: 2011-05-03 12:01:14
kharkov_max
awk не годится т.к. awk уже используется для преобразования, разве что если можно как то вложенный awk использовать

Вся конструкция выглядит так:

Код: Выделить всё

gawk '{FS="[ ]+"} {print "INSERT INTO .....VALUES (" ..... ,\""$2"\", .... ,\""$14"\", .....} '  |  tr \ \"\,\" > /file
Вот в $14 содержится то что я хотел преобразовать при помощи tr, если возможно через awk или gawk подскажите пожалуйста как ?

Re: Подскажите с tr

Добавлено: 2011-05-03 12:04:36
FreeBSP
дай десяток-другой строк из лога

Re: Подскажите с tr

Добавлено: 2011-05-03 12:10:10
rmn
kharkov_max писал(а):awk не годится т.к. awk уже используется для преобразования, разве что если можно как то вложенный awk использовать
в awk есть функция sub для замены подстрок

можно и так, если в строке только один символ \ (тот, что нужно заменить):

Код: Выделить всё

gawk '{FS="[ ]+"} {print "INSERT INTO .....VALUES (" ..... ,\""$2"\", .... ,\""$14"\", .....} '  |  awk -F\\ '{print $1"\",\""$2}' > /file

Re: Подскажите с tr

Добавлено: 2011-05-03 15:58:21
kharkov_max
rmn писал(а):
kharkov_max писал(а):awk не годится т.к. awk уже используется для преобразования, разве что если можно как то вложенный awk использовать
в awk есть функция sub для замены подстрок

можно и так, если в строке только один символ \ (тот, что нужно заменить):

Код: Выделить всё

gawk '{FS="[ ]+"} {print "INSERT INTO .....VALUES (" ..... ,\""$2"\", .... ,\""$14"\", .....} '  |  awk -F\\ '{print $1"\",\""$2}' > /file
Вы правы в принципе так должно работать ... Что то не додумался до этого ...
Но !!!

Цель деления $14 было получить $14 (слово1) и $15 (слово2), но по определенным причинам $14 может быть изначально пустым - символ "-".
Вот тут как то нужно $14 делить в любом варианте на $14 и $15 с пустыми значениями или с каким нить символом, хотя бы "-".
Т.е. что б в /file получилось "-","-" -> ($14,$15) из первичного $14 ...

Re: Подскажите с tr

Добавлено: 2011-05-03 21:35:51
kpp
Дайте лог посмотреть, а то так пальцем в небо.

Re: Подскажите с tr

Добавлено: 2011-05-04 10:02:47
kharkov_max
kpp писал(а):Дайте лог посмотреть, а то так пальцем в небо.
Вот:

Код: Выделить всё

1304491986.626      1 - 192.168.0.1 192.168.0.1 1864 - TCP_HIT 200 333 799 1132 http://forum.lissyara.su/styles/prosilver/theme/medium.css DOMAIN\user text/css 1.1 GET
1304492037.197      1 - 192.168.0.2 proxy1 49018 - TCP_MISS 200 6649 57 6706 cache_object://localhost/active_requests - text/plain 1.0 GET
Не буду скрывать, это лог Squid - пишу свой анализатор через Mysql.
Уже все работает и пишется в Mysql, так же есть универсальная процедура которая может выбирать из базы любые данные.
Единственная проблема это как правильно разделить DOMAIN\user указать домен в конфиге Squid нельзя, т.к. домена 2 (squid обслуживает 2 домена).
Лепить данное разделение в Mysql не хочу, хочу разделить на уровне парсинга лога т.е. через shell.
1я строка лога это с авторизацией, 2я там где поле DOMAIN\user пустое = "-".

Еще раз спасибо за помощь.

Re: Подскажите с tr

Добавлено: 2011-05-04 11:40:25
rmn
parselog.sh

Код: Выделить всё

#!/bin/sh

while read a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17
do
    domain=""
    user=""

    if [ "$a14" != "-" ];
    then
        echo $a14 | awk -F\\ '{print $1,$2}' | read domain user
    fi

    echo "INSERT INTO ... (... , $domain, $user, ...)"
done

Код: Выделить всё

% cat squid.log | parselog.sh > file

Re: Подскажите с tr

Добавлено: 2011-05-04 11:51:22
kharkov_max
Спасибо.

Тоже думал про такую схему, но пугал цикл.
Хотелось меньше комп грузить при парсинге, да и скорость отработки увеличить, но похоже придется переписать скрипт как Вы предложили.

Re: Подскажите с tr

Добавлено: 2011-05-04 11:56:06
rmn
kharkov_max писал(а): Хотелось меньше комп грузить при парсинге, да и скорость отработки увеличить
такой вариант как раз будет быстрее и меньше будет систему нагружать, потому что строка будет разбиваться на составляющие встроенной функцией, а не внешней программой.

Re: Подскажите с tr

Добавлено: 2011-05-04 12:45:33
kharkov_max
while read гасит разделитель "\" из лога.
Т.е. в логе $14 = DOMAIN\user в цикл while попадает как DOMAINuser соответственно вся остальная конструкция не работает.

Если в логе разделитель поправить на \\ то в цикл попадает как нужно в виде DOMAIN\user.

Re: Подскажите с tr

Добавлено: 2011-05-04 13:21:53
kharkov_max
Конструкция вида

Код: Выделить всё

echo $a14 | read domain
echo $a14 $domain
Не работает ((( $domain пустой ...

Re: Подскажите с tr

Добавлено: 2011-05-04 16:20:22
kharkov_max
Если интерестно, то решил эту задачу так:

Код: Выделить всё

$gawk '{FS="[ ]+"}
        {if ($14 != "-") { split($14,a,"\\");
                   print "INSERT INTO log .........
                   VALUES ("strftime("%Y%m%d%H%M%S",$1)",\""$2"\",\""$3"\", \
                   \""$4"\",\""$5"\","$6",\""$7"\",\""$8"\","$9","$10","$11","$12",\""$13"\",\""a[1]"\",\""a[2]"\", \
                   \""$15"\",\""$16"\",\""$17"\");"; }
               else { d="-";u=$14;
                   print "INSERT INTO log .....
                   VALUES ("strftime("%Y%m%d%H%M%S",$1)",\""$2"\",\""$3"\", \
                   \""$4"\",\""$5"\","$6",\""$7"\",\""$8"\","$9","$10","$11","$12",\""$13"\",\""$14"\",\""$14"\", \
                   \""$15"\",\""$16"\",\""$17"\");" }
         }' $squid_log_file > $tmp_file
Самый красивый вариант ))).
gawk - жжот ...

Re: Подскажите с tr

Добавлено: 2011-05-04 16:31:09
kharkov_max
http://www.math.spbu.ru/user/rus/cluste ... glav.shtml - рекомендую ...
Может кому пригодится.

Re: Подскажите с tr

Добавлено: 2011-05-04 17:29:48
kpp
Обычным awk такое не сделать?

Re: Подскажите с tr

Добавлено: 2011-05-04 17:38:37
kharkov_max
kpp писал(а):Обычным awk такое не сделать?
Уже не помню из каких соображений ставил gawk ....
Не копал в эту сторону, но скорее всего что можно, нужно глянуть есть ли в awk split и его синтаксис.

Ну и

Код: Выделить всё

cat ./file | awk '{....}' > ./tmp_file
В теории должно получится.

Re: Подскажите с tr

Добавлено: 2011-05-04 17:55:54
kharkov_max
kpp писал(а):Обычным awk такое не сделать?
А вот и ответ на Ваш вопрос.
В awk нет функции strftime, а она мне нужна для преобразования времени из timestamp.

А так, все должно работать и в awk.

Re: Подскажите с tr

Добавлено: 2011-05-04 19:13:55
kpp
В обычном awk есть split и не обязательно делать

Код: Выделить всё

cat ./file | awk '{....}' > ./tmp_file
конструкция

Код: Выделить всё

awk '{....}' ./file > ./tmp_file
доступна и предпочтительна.
На счет функций, да, наверняка(нужно проверить) такой ф-ции нет, но это преобразование можно делать отдельно перед awk.

Re: Подскажите с tr

Добавлено: 2011-05-04 20:46:12
FreeBSP
а пых/перл приколупать сюда не позволяют какие соображения?
да, менее православно чем шелл, но зато полно шустрых инструментов для обработки строк, оптимизации запросов и тд

кстати эфффективнее запихивать в базу пачки по 10-10000строк одним запросом,, чем на каждую строку выполнять запрос
суммарно по времени на обработку 1млн строк может выйти и эффективнее чем шелл.