Форум русскоязычного сообщества Ubuntu


Хотите сделать посильный вклад в развитие Ubuntu и русскоязычного сообщества?
Помогите нам с документацией!

Автор Тема: Помогите решить задачку sed  (Прочитано 1356 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн nrubanov

  • Автор темы
  • Новичок
  • *
  • Сообщений: 8
    • Просмотр профиля
Помогите решить задачку sed
« : 04 Июня 2014, 13:18:18 »
Ребята помогите решить задачу, а то с sed что то я никак разобраться не могу, а допилить shell скрипт во как нужно.

Исходные условия:

Дописываю скрипт мониторинга по словам.

Есть некий скрипт, который делает запрос к базе Mysql и выгружает результат в файл. Далее данные сверяются со вторым файлом ( Стоп слова ) и результат совпадений выводится в третий. Далее все это формируется в html письмо и отправляется на почту.

Пример выгрузки:

user_id originator      phone   lower(text)     date
1002    VsyNakhodka     79143407831     490 - ваш код потверждения номера телефона в приложении вся находка     2014-06-04 11:01:47
1221    BazaB2B 79049837084     снять жилье от собственников - сайт bazab2b.ru. все варианты модери     2014-06-04 11:01:53
1002    Settle  79144079009     ул.вахова, тип: 3х-комнатная квартира, цена: 27000, тел.: 891454674     2014-06-04 11:01:53
1221    BazaB2B 79049837084     руются и выставляются в режиме on-line  2014-06-04 11:01:53
1002    Settle  79144079009     53, имя: евгения        2014-06-04 11:01:53

Файл со словами:



bombey
energy

Сейчас итоговое письмо выглядит примерно так:

Обнаружены смс, содержащие стоп слова:

Id пользователя;  Имя; Номер абонента; Текст; Дата;

1002 Baraban Dom 79122210803   барабаны с обиди на каникулы ушли! до сентября! +79122122222   2014-06-04 12:42:03

Список стоп слов:

а,б,в и т.д


Нужно чтобы те слова, которые обнаружены в тексте каким то образом выделялись.

По моей логике нужно делать следующее:

1) Сделать сравнение списка стоп слов и итогового результата, и там где есть совпадение подставить перед словом <bold> и после него закрыважщий тег </bold>, так как формат html этого вполне достаточно. Насколько я понял все это
можно реализовать с помощью sed, но как написать такую громоздкую конструкцию я ума не приложу.

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

Оффлайн SvMidi

  • Активист
  • *
  • Сообщений: 815
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #1 : 04 Июня 2014, 14:12:12 »
ищешь grep, меняешь sed
Я знаю только то, что ничего не знаю, остальные не знают и этого.

Оффлайн nrubanov

  • Автор темы
  • Новичок
  • *
  • Сообщений: 8
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #2 : 04 Июня 2014, 17:41:29 »
Да это то понятно - так и делаю.

Для начала:

fgrep файл_со_словами файл_с_выгрузкой > результат

А вот c sed беда, нашел похожую проблему в соседней теме https://forum.ubuntu.ru/index.php?topic=244641.0

Но это не совсем мой случай. Не понимаю как ему одновременно два файла подсунуть, да так чтоб он их верно обработал.

Оффлайн SvMidi

  • Активист
  • *
  • Сообщений: 815
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #3 : 04 Июня 2014, 20:44:03 »
Стоп-слов то много?
Если не много я бы сделал так:
файл содержащие стоп-слова генерируется MySQL (WHERE LIKE ...)
Читал бы файл со словами построчно (одно стоп-слово - одна строка)
и натравливал бы на него каждое слово примерно так:
sed -i "s/$word/<b>$word<\/b>/g"хотя можно по всякому извернуться
Я знаю только то, что ничего не знаю, остальные не знают и этого.

Оффлайн nrubanov

  • Автор темы
  • Новичок
  • *
  • Сообщений: 8
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #4 : 04 Июня 2014, 21:01:53 »
Стоп слов штук 50 и постоянно будут меняться и добавляться. Причем редактироваться файл будет через php админку.

Так что файл такого типа использовать не получится:

cat file | sed -i "s/слово1/<b>СЛОВО1<\/b>/g" &&
cat file | sed -i "s/слово2/<b>СЛОВО2<\/b>/g" &&
cat file | sed -i "s/слово3/<b>СЛОВО3<\/b>/g"

Хотя конечно очень хочется, но буду делать сразу по уму.

По одной фразе sed меняет без проблем, а с циклической заменой я пока не разобрался.
Сегодня куча документации перечитал и примеров много посмотрел, но конкретного конечного решения так и не придумал.

Основная проблема в том, что изначально задумывалось выгружать раз в час весь массив данных, а затем его уже разгребать встроенными утилитами. Если по каждой фразе запрос делать, то слишком долго скрипт выполняться будет.
« Последнее редактирование: 04 Июня 2014, 21:11:02 от nrubanov »

Оффлайн SvMidi

  • Активист
  • *
  • Сообщений: 815
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #5 : 04 Июня 2014, 21:07:15 »
#/bin/bash
fgrep -f words.txt unloading.txt > result.html
cat words.txt | while read word
do
    sed -i "s/$word/<b>$word<\/b>/g" result.html
done
Я знаю только то, что ничего не знаю, остальные не знают и этого.

Оффлайн nrubanov

  • Автор темы
  • Новичок
  • *
  • Сообщений: 8
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #6 : 04 Июня 2014, 21:14:12 »
Спасибо.

То есть я правильно понимаю что конструкция cat words.txt | while read word
будет читать построчно строки из words.txt ?

Оффлайн Azure

  • Модератор раздела
  • Старожил
  • *
  • Сообщений: 6017
  • Windows10, i3wm on Debian9, Manjaro20.0
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #7 : 04 Июня 2014, 21:16:18 »
Если стоп-слов много, то нужно считывать их по одному и "скармливать" sed
Код: (bash) [Выделить]
while read stop_word;
do
  sed -n '/$stop_word/s//<b>\&<\/b>/gw файл_результат' файл-выгрузка;
done < файл_с_стоп-словами
Но в этом случае если в одной строке будет несколько стоп-слов то строка повторится несколько раз каждый раз выделяя другое стоп-слово.
« Последнее редактирование: 04 Июня 2014, 21:18:12 от Azure »
В Linux можно сделать ВСЁ что угодно, достаточно знать КАК !

Оффлайн SvMidi

  • Активист
  • *
  • Сообщений: 815
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #8 : 04 Июня 2014, 21:42:45 »

Я ещё нагородил#/bin/bash
WORDS=файл стоп-слова
UNLOADING=файл выгрузки
READY=файл с результатом


fgrep -f $WORDS $UNLOADING > $READY
ca=`
cat $WORDS | while read word
do
    ca="s/$word/<strong>$word<\/strong>/g;"
    echo $ca
done
`
sed -i "$ca" $READY

Пользователь решил продолжить мысль 04 Июня 2014, 21:44:56:

Azure, как Вы так код оформили?
« Последнее редактирование: 04 Июня 2014, 21:45:31 от SvMidi »
Я знаю только то, что ничего не знаю, остальные не знают и этого.

Оффлайн Azure

  • Модератор раздела
  • Старожил
  • *
  • Сообщений: 6017
  • Windows10, i3wm on Debian9, Manjaro20.0
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #9 : 04 Июня 2014, 21:50:54 »
SvMidi,
(Нажмите, чтобы показать/скрыть)
В Linux можно сделать ВСЁ что угодно, достаточно знать КАК !

Оффлайн nrubanov

  • Автор темы
  • Новичок
  • *
  • Сообщений: 8
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #10 : 05 Июня 2014, 11:43:09 »
Эх, не работает ни одна из конструкций, на выходе пустой файл.

root@platforma:/usr/home/easy-sms/data/new_platform/frod # uname -a
FreeBSD platforma.easy-sms.ru 9.1-RELEASE FreeBSD 9.1-RELEASE #0: Sun May  4 01:53:59 MSK 2014     root@platforma.easy-sms.ru:/usr/src/sys/amd64/compile/PLATFORMA1-NODE1  amd64

[root@platforma /usr/home/easy-sms/data/new_platform/frod]# bash --version
bash --version
GNU bash, version 4.2.45(0)-release (amd64-portbld-freebsd9.1)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Оффлайн SvMidi

  • Активист
  • *
  • Сообщений: 815
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #11 : 05 Июня 2014, 12:14:11 »
Надо было сразу сказать. Что хоть пишет?
В FreeBSD bash находится в /usr/local/bin/bash, надо изменить первую строку
« Последнее редактирование: 05 Июня 2014, 12:15:47 от SvMidi »
Я знаю только то, что ничего не знаю, остальные не знают и этого.

Оффлайн nrubanov

  • Автор темы
  • Новичок
  • *
  • Сообщений: 8
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #12 : 05 Июня 2014, 13:13:04 »
Cпасибо большое - разобрался.

Заработала в итоге такая конструкция:

#!/usr/local/bin/bash
cat swear_words.txt | while read word
do
sed -i -e "s/$word/<strong><font color="#ff0000">$word<\/font><\/strong>/g" mailmessage
done

P.S. Как скрипт допишу - сюда код кину, авось кому пригодится.
« Последнее редактирование: 05 Июня 2014, 13:15:21 от nrubanov »

Оффлайн Azure

  • Модератор раздела
  • Старожил
  • *
  • Сообщений: 6017
  • Windows10, i3wm on Debian9, Manjaro20.0
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #13 : 05 Июня 2014, 17:16:27 »
Привыкайте записывать первую строчку скрипта (sha-bang + интерпретатор)sed "1i\#\!$(which bash)" script.file
В Linux можно сделать ВСЁ что угодно, достаточно знать КАК !

Оффлайн nrubanov

  • Автор темы
  • Новичок
  • *
  • Сообщений: 8
    • Просмотр профиля
Re: Помогите решить задачку sed
« Ответ #14 : 05 Июня 2014, 17:24:05 »
Вот итоговая версия скрипта
#!/usr/local/bin/bash
###############################################
# Frod мониторинг - версия от 05.06.2014 ######
###############################################

####################################################################
# Необходимы следующие установленные приложения для работы скрипта #
# bash, mysql, sendmail, uniq, sort, sed, fgrep, base64 ############
####################################################################

#########################
# Объявляем пути: #######
#########################

# Расположение используемых приложений
# fgrep
fgrep="/usr/bin/fgrep"
# mysql
mysql="/usr/local/bin/mysql"
# echo
echo="/bin/echo"
# mail
sendmail="/usr/sbin/sendmail"
# cat
cat="/bin/cat"
# rm
rm="/bin/rm"
# sort
sort="/usr/bin/sort"
# uniq
uniq="/usr/bin/uniq"
# sed
sed="/usr/bin/sed"
# base64
base64="/usr/local/bin/base64"

# Почтовые настройки
# Адрес ящика, на который отправляем отчет
toemail="admin@admin.ru"
# Адрес ящика, с которого отправляем отчет
fromemail="otchet@otchet.ru"
# Тема письма
subject="тема письма"

# Mysql настройки
# Пользователь для подключения к серверу Mysql
mysql_login="mysqluser"
# Пароль для подключения к серверу Mysql
mysql_password="12345678"
# IP сервера Mysql
dbhost="localhost"
# Имя базы
database="base"
# Кодировка запроса
encoding="koi8r"

# Временные интервалы
# Вывод текущего времени, в формате, пригодном для использования в mysql
date_time=`date +"%Y-%m-%d %H:%M:%S"`
# Интервал -1 час от текщей даты
date_time_1=`date -v-1H +"%Y-%m-%d %H:%M:%S"`

# Файлы и папки
datadir="/usr/home/123"
# Для временных результатов используем файлы
# Лучше конечно задействовать переменные, но при их использовани не всегда корректно отоброжаются данные
# Например при сохранении результата запроса к mysql в временный файл все отоброжается корректно ( Строки с переносами )
# При выводе результата в переменную все даннуе почему то пишутся в одну строку и хрен его знает как это все нормально отображать.
# На всякий случай - как работать с переменными:
# Запись результата выполнения комманды в переменную а=`имя команды`, например a=`date`
# Вывод значения переменной echo $a, также можно выводить данные из переменной в другое место - например echo $a > 123
# В данном случае мы выводим данные из переменной a в файл 123. С файлами вроде работает достаточно быстро, так что оставляю пока все в таком виде.
result="query_result"
words="swear_words.txt"
outcome="outcome"
outcome1="outcome1"
mailmessage="mailmessage"
words2="words2"
# Почемуто при использовании sed -i -e, появляется файл с окончанием -e, без данного атрибута не работает, да и фиг с ним - одним файлом больше, одним меньше
# Здесь указываем временный файл sed, после всех операций прибиваем его
temp="outcome1-e"

# Начинаем процесс
# Делаем запрос к базе mysql и выгружаем данные в файл
# В запросе используем lower, для того чтобы преобразовать все буквы в нижний регистр ( Все стоп слова в файле swear_words.txt должны быть написаны в нижнем регистре )
$mysql -u $mysql_login -p$mysql_password -h $dbhost --force --one-database $database  --default-character-set=$encoding -e "SELECT  user_id, originator, phone, lower(text), date FROM stat_details WHERE date > '$date_time_1'" > /$datadir/$result

# Ищем совпадения по фразам из файла и выгружаем результат
# -i регистронезависимо, по факту с русскими символами не работает
# -f файл
$fgrep -if $datadir/$words $datadir/$result > $datadir/$outcome1

# Обрабатываем выгрузку ( Этап 1 ) - Удаляем строки с одинаковым содержанием ( Дополнительная защита )
$sort $datadir/$outcome1 | $uniq -u > $datadir/$outcome

# Удаляем временный файл
$rm $datadir/$outcome1

# Обрабатываем выгрузку ( Этап 2 ) - Заменяем символы переноса строки unix на символы переноса строки html
$sed 's/$'"/`echo \\\'<br>'`/" $datadir/$outcome > $datadir/$outcome1

# Обрабатываем выгрузку ( Этап 4 ) - Стоп слова помечаем жирным, цвет красный
$cat $datadir/$words | while read word
do
$sed -i -e "s/$word/<strong><font color="#ff0000">$word<\/font><\/strong>/g" $datadir/$outcome1
done

# Переводим стоп слова из столбика в строку, для удобства восприятия письма ( Используем переменную а )
a=`$cat $datadir/$words`
echo $a > $datadir/$words2

# Если файл размером больше 0, то добавляем примечания и отправляем предупреждение на почту
if [ -s $datadir/$outcome ]; then

# Отправляем почту
# Для нативной отправки почты можно использовать два встроенных приложения mail и sendmail, также mutt и т.д.
# Как показало тестирование mail не умеет корректно отправлять html сообщения, так что для наших целей будем использовать sendmail
# Для справки:
# Отправка сообщения из mail - mail -s "Тема сообщения" e-mail_получателя < Вложение
# Отправка сообщения из sendmail - sendmail e-mail_получателя < Вложение
# Остальные атрибуты sendmail берет из файла с сообщением

##########################################
### Приступаем к формированию письма #####
##########################################

# Для начала определеям произвольный, уникальный id
boundary="frod-`date +%s`-$$"
# Пишем заголовки
# От какого адреса придет письмо
$echo "From: $fromemail" > $datadir/$mailmessage
# На какой ящик придет письмо
$echo "To: $toemail" >> $datadir/$mailmessage
# Тема письма
$echo "Subject: $subject" >> $datadir/$mailmessage
# Версия MIME
$echo "Mime-Version: 1.0" >> $datadir/$mailmessage
# Пишем заголовок сообщения и id
# multipart/mixed означает, что письмо состоит из нескольких частей, каждая из которых содержит свой заголовок Content-type
$echo "Content-Type: multipart/mixed; boundary=$boundary" >> $datadir/$mailmessage
# Начинаем заполнять первую часть сообщения
# Пишем id ( Впереди обязательно должны стоять -- )
$echo "--$boundary" >> $datadir/$mailmessage
# Объявляем что письмо у нас в формате html, кодировка письма koi8-r
$echo "Content-Type: text/html; charset=koi8-r" >> $datadir/$mailmessage
# Начинаем наполнять html содержимым
# Вставляем html заголовки
$echo "<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">" >> $datadir/$mailmessage
$echo "<html xmlns="http://www.w3.org/1999/xhtml">" >> $datadir/$mailmessage
$echo "<head>" >> $datadir/$mailmessage
# Задаем стили
$echo "<style type="text/css">" >> $datadir/$mailmessage
$echo "body {" >> $datadir/$mailmessage
$echo "font-family: "Times New Roman", Times, serif;" >> $datadir/$mailmessage
$echo "font-size: 8px;" >> $datadir/$mailmessage
$echo "font-style: normal;" >> $datadir/$mailmessage
$echo "}" >> $datadir/$mailmessage
$echo "</style>" >> $datadir/$mailmessage
$echo "</head>" >> $datadir/$mailmessage
$echo "" >> $datadir/$mailmessage
$echo "<body>" >> $datadir/$mailmessage
# Формируем таблицу для данных
$echo "<table width="800px" border="1" cellspacing="0" cellpadding="5px" bordercolor="#CCCCCC">" >> $datadir/$mailmessage
$echo "<tr>" >> $datadir/$mailmessage
$echo "<th align="left">" >> $datadir/$mailmessage
# Вставляем начальную строку и данные
$echo "<img src="cid:frodlogo" />" >> $datadir/$mailmessage
$echo "<h2>Обнаружены смс, содержащие стоп слова:</h2>" >> $datadir/$mailmessage
$echo "<h3>Id пользователя;  Имя; Номер абонента; Текст; Дата;</h3>" >> $datadir/$mailmessage
# Вставляем результаты выгрузки, после сортировки и обработки
$cat $datadir/$outcome1 >> $datadir/$mailmessage
$echo "<br>" >> $datadir/$mailmessage
$echo "<h3>Список стоп слов:</h3>" >> $datadir/$mailmessage
# Вставляем список стоп слов
$cat $datadir/$words2 >> $datadir/$mailmessage
$echo "</th>" >> $datadir/$mailmessage
$echo "</tr>" >> $datadir/$mailmessage
$echo "</table>" >> $datadir/$mailmessage
$echo "</body>" >> $datadir/$mailmessage
$echo "</html>" >> $datadir/$mailmessage
$echo "" >> $datadir/$mailmessage
$echo "--$boundary" >> $datadir/$mailmessage
# Добавляем следующую часть ( Картинка )
$echo "Content-Type: image/jpg;" >> $datadir/$mailmessage
$echo "Content-Transfer-Encoding: base64" >> $datadir/$mailmessage
$echo "Content-Disposition: inline; filename=frodlogo.jpg" >> $datadir/$mailmessage
$echo "Content-ID: <frodlogo>" >> $datadir/$mailmessage
$echo "" >> $datadir/$mailmessage
# Кодируем картинку и добавляем в конец файла
$cat $datadir/frodlogo.jpg | $base64 >> $datadir/$mailmessage
$echo "" >> $datadir/$mailmessage
$echo "--$boundary" >> $datadir/$mailmessage
# Отправляем письмо
$sendmail $toemail < $datadir/$mailmessage
# Удаляем временные файлы
$rm $datadir/$mailmessage
$rm $datadir/$result
$rm $datadir/$outcome
$rm $datadir/$outcome1
$rm $datadir/$words2
$rm $datadir/$temp
exit
fi
# Иначе
# Удаляем временные файлы
$rm $datadir/$result
$rm $datadir/$outcome
$rm $datadir/$outcome1
$rm $datadir/$words2
# Говорим что все хорошо
echo В выгрузке не обнаружено стоп слов, беспокоиться не стоит.
exit


В итоге раз в час получаем на почту письмо примерно следующего содержания



Что собственно и требовалось, большее спасибо за помощь.
« Последнее редактирование: 05 Июня 2014, 17:51:05 от nrubanov »

 

Страница сгенерирована за 0.037 секунд. Запросов: 22.