URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 8804
[ Назад ]

Исходное сообщение
"Bash Скрипт обработка писем или текстовых файлов"

Отправлено ILYA INDIGO , 14-Июл-10 22:03 
:) Здравствуйте :)

Помогите написаить скрипт, который бы перебирал все письма в указанной папке, и выводил на консоль определённую информацию о этих письмах, а именно:
1 Имя файла
2 все IP адреса, встречающиеся в заголовках Received: письма;
3 все доменные имена, встречающиеся в теле письма.

В формате:

"Имя файла1"

Доменные имена из тела:
"Доменное имя 1"
"Доменное имя 2"
...
"Доменное имя n"

IP адреса из заголовка в строках начинающимся словом Received:
"IP 1"
"IP 2"
...
"IP n"

"Имя файла 2"
,,,
и т.д. для всех файлов, находящихся в указанной директории (например ./mail)


Задача, как я представляю, состоит из следующих этапов:

1.1 Передор директории ./mail
1.2 Вывод имени файла на консоль
2.1 Обработка тела писем и получение из них URL-ей email-ов и доменов (Тела письем от заголовков отделено пустой строкой)
2.2 Преобразование доменых имён из ранее полученных URL-ей (отфильровать текст между / и /) (http://vasya.narod.ua/forum/index.php -> vasya.narod.ua)
2.3 Преобразование доменых имён из ранее полученных email-ов (отфильтровать слова, содержащие @ и оставить только, то что после @) (vasya@narod.ua -> narod.ua)
2.4 Вывод всех полученных и преобразованных доменов из тела письма на консоль
3.1 Обработка заголовка писеми и получение из строк, начинающихся на Received: доменных имён и IP-адресов. (Заголовк начинаеться от начала письма, и кончается первой пустой строкой)
3.2 Преобразование доменных имён в IP-адреса. (vasya.narod.ua -> 109.10.158.16)
3.3 Вывод всех полученных и преобразованных IP-адресов из заголовка в консоль
4   Повторять цикл, пока не переберуться все файлы в директории ./mail

Подозреваю что  пункты 2 и 3 можно выполнить не деля их на подпункты, но пока незнаю через что именно их делать sed или awk или ещё через что то.

Пока только справился с 1 и 4 пунктами:

#!/bin/bash
DIR="./mail"
find $DIR -type f | while read FILE_NAME;
    do
        echo -e "\n\t$FILE_NAME"
        echo -e "\tdomain names:"
        cat $FILE_NAME | while read LINE
            do
                echo "$LINE"
            done
        echo -e "\tIPs:"
    done

Для удобства архив с папкой и письмами можно скачать отсюда http://ILYA.pp.ua/m.7z

Надеюсь, если и не на полное решение, то на частичное, а так же направление в нужную сторону :))


Содержание

Сообщения в этом обсуждении
"Bash Скрипт обработка писем или текстовых файлов"
Отправлено ILYA INDIGO , 14-Июл-10 22:41 
Received: (qmail 32088 invoked from network); 7 Jan 2003 09:29:25 -0000
Received: from dev213.mailshell.com (HELO mailshell.com) (@71.129.195.163)
  by dev50.mailshell.com with SMTP; 7 Jan 2003 09:29:25 -0000
Received: (qmail 23535 invoked by uid 99); 7 Jan 2003 09:29:25 -0000
Received: (qmail 6505 invoked from network); 7 Jan 2003 09:29:24 -0000
Received: from unknown (HELO qmail8.arcamax.com) (209.96.210.81)
  by www.mailshell.com with SMTP; 7 Jan 2003 09:29:24 -0000
Received: (qmail 15185 invoked from network); 7 Jan 2003 09:29:30 -0000
Received: from qmail8.arcamax.com (209.96.210.81)

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

Но иногда бывает что перед IP адрессом стоит символ @

(@71.129.195.163)


"Bash Скрипт обработка писем или текстовых файлов"
Отправлено L0n3R4ng3r , 15-Июл-10 12:22 
> хотелось бы знать как можно преобразовать домен в IP, например использую ping или что то > подобное.

dig +short domen.com a


"Bash Скрипт обработка писем или текстовых файлов"
Отправлено ILYA INDIGO , 15-Июл-10 15:41 
>> dig +short domen.com a

Спасибо большое за ответ :)

На данный момент у меня код:

#!/bin/bash
clear
DIR="./mail"
find $DIR -type f | while read FILE_NAME;
    do
        echo -e "\n$FILE_NAME"
        echo "domain names:"
        echo "IPs:"
        awk '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[\)\]]/ {print substr($NF,2,length($NF)-3)}' $FILE_NAME
    done

Где вро де бы и решил, частично, вывод всез IP-адресов, но всё же это далеко не идеал.

1 Я Используя NF, в качестве разпознователя поля с IP, предпологаю, что IP лежит всегда в конце строки. В большинстве случаев это так, но НЕ всегда.
2 Я предпологаю, что IP заключён всегда в круглые скобки, и при показе последнюю закрывающую скобку (последний символ поля) отбрасываю. И это не всегда так :(, так как некоторые IP умудряются быть записанныуми и в таком вот виде ([127,0,0,1]) т.е. заключённые сразу в 2 пары скобок, хотя теоретичиски предпологая, что может и попасться вариант вообще без скобок.
3 Так что нужен цикл вывода только IP адресов, читающих их от первой цифры до последний цифры, при условии, что эти цифры могут заключаться в круглые () скобки или квадратные скобки [] или в обоя сразу, а так же могут быть заключены в пробел и/или символ переноса строки \n  в различных вароиациях (томеж находиться в начале строки, в середине строки или в конце строки.) А так же зона обработки должна быть от начала файла, и останавливаться, при обнаружениии первой пустой строки, как я понял при обнаружении \n\n, а дальше break в цикле или что т о тому подобное.

Помогите пожалуйста реализовать, хотя бы, эту задачу, можно да же и не на awk, и даже не на Boerne Shell вообще (например Perl, Python, C/C++) уже более суток НЕ спал и голова совсем НЕ соображает уже :(


"Bash Скрипт обработка писем или текстовых файлов"
Отправлено L0n3R4ng3r , 15-Июл-10 18:26 
>[оверквотинг удален]
>символ переноса строки \n  в различных вароиациях (томеж находиться в
>начале строки, в середине строки или в конце строки.) А так
>же зона обработки должна быть от начала файла, и останавливаться, при
>обнаружениии первой пустой строки, как я понял при обнаружении \n\n, а
>дальше break в цикле или что т о тому подобное.
>
>Помогите пожалуйста реализовать, хотя бы, эту задачу, можно да же и не
>на awk, и даже не на Boerne Shell вообще (например Perl,
>Python, C/C++) уже более суток НЕ спал и голова совсем НЕ
>соображает уже :(

я бы посоветовал использовать perl все таки он изобретен для обработки текста и как никто лучше справляеться с єтой задачей


для айпишников цикл будет выглядеть примерно так :


use Socket;

my $file = 'path/to/file';
my @ips;
open(FILE,"<$file");
while(<FILE>){
if ( /(\d+\.\d+\.\d+\.\d+)/  ){
   my $ip = $1;
   @ips = push(@ips,$ip); #для того чтобы поместить айпишник в масив ips(если нужно)
   print "$ip\n"; # для того чтобы вывести его
   $ip = inet_aton($ip);
   $name  = gethostbyaddr($ip, AF_INET); # для того чтобы вернуть его доменое имя
}
}


ну вот где-то так.. печатал сразу тут так что на ерроры не проверял.


"Bash Скрипт обработка писем или текстовых файлов"
Отправлено McLeod095 , 16-Июл-10 17:00 
>[оверквотинг удален]
>   print "$ip\n"; # для того чтобы вывести его
>   $ip = inet_aton($ip);
>   $name  = gethostbyaddr($ip, AF_INET); # для того чтобы
>вернуть его доменое имя
> }
>}
>
>
>ну вот где-то так.. печатал сразу тут так что на ерроры не
>проверял.

лучше наверное используйте все таки перл. Он точно со всем справится, и будет довольно удобно.
Ну и почитайте книжку по регулярным выражениям.
Вот регулярное выражение для поиска IP адреса который приведен в этой книге
^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$



"Bash Скрипт обработка писем или текстовых файлов"
Отправлено L0n3R4ng3r , 16-Июл-10 18:11 
>[оверквотинг удален]
>>
>>ну вот где-то так.. печатал сразу тут так что на ерроры не
>>проверял.
>
>лучше наверное используйте все таки перл. Он точно со всем справится, и
>будет довольно удобно.
>Ну и почитайте книжку по регулярным выражениям.
>Вот регулярное выражение для поиска IP адреса который приведен в этой книге
>
>^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$

Спасибо за заботу по-поводу книжки по регекспам, но должен вас разочеровать даный регексп не рабочий. Визуально он вроди бы составлен правильно, но на практите это не так:
$ echo '1' | perl -ne '/([01]?\d\d?|2[0-4]\d|25[0-5])/; print "$1\n"'
1
$ echo '10' | perl -ne '/([01]?\d\d?|2[0-4]\d|25[0-5])/; print "$1\n"'
10
$ echo '110' | perl -ne '/([01]?\d\d?|2[0-4]\d|25[0-5])/; print "$1\n"'
110
$ echo '232' | perl -ne '/([01]?\d\d?|2[0-4]\d|25[0-5])/; print "$1\n"'
23
$ echo '255' | perl -ne '/([01]?\d\d?|2[0-4]\d|25[0-5])/; print "$1\n"'
25

Тоесть октеты начинающиеся на 2хх тупо режуться до двух первых символов. И вообще использовать его в коде не очень хорошая идея если вы еще хотите использовать этот код :)

Проще использовать такой регексп - /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/ . У него есть минимальное количество проверок на валидность, правда намного меньше чем в вашем, но такие проверки на 99.9% бесполезны.


"Bash Скрипт обработка писем или текстовых файлов"
Отправлено ILYA INDIGO , 17-Июл-10 15:10 
>Вот регулярное выражение для поиска IP адреса который приведен в этой книге
>
>^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$

При таком алгоритме вывод вообще пустой, а если убрать ^ в начале и $, то аналогичен вы воду Второго алгоритма т.е.

71
63
10


"Bash Скрипт обработка писем или текстовых файлов"
Отправлено ILYA INDIGO , 17-Июл-10 14:58 
>я бы посоветовал использовать perl все таки он изобретен для обработки текста
>и как никто лучше справляеться с єтой задачей
>
>ну вот где-то так.. печатал сразу тут так что на ерроры не
>проверял.

Ок спасибо за совет и ответ, я таки, буду пытаться это переделать на PERL-е.

Но алгоритм всё равно не работает должным образом...

Вот фрагмент текста письма, находящегося в файле: ./mail/111

Received: (qmail 29944 invoked from network); 8 Jan 2003 07:10:33 -0000
Received: from dev212.mailshell.com (HELO mailshell.com) (71.129.195.163)
  by dev50.mailshell.com with SMTP; 8 Jan 2003 07:10:33 -0000
Received: (qmail 26211 invoked by uid 99); 8 Jan 2003 07:10:33 -0000
Message-ID: <20030108071033.15907.qmail@mailshell.com>
Received: (qmail 13669 invoked from network); 8 Jan 2003 07:10:31 -0000
Received: from unknown (HELO anclsmtp03.myfamily.com) (63.92.90.192)
  by www.mailshell.com with SMTP; 8 Jan 2003 07:10:31 -0000
Received: from ancnews01 (10.6.8.151) by anclsmtp03.myfamily.com (LSMTP for Windows NT v1.1b) with SMTP id <22.00312C4E@anclsmtp03.myfamily.com>; Wed, 8 Jan 2003 0:11:17 -0700
X-Sender: <unsubscribe.nbrc8744.000001.1048576.0.0@unsubscribe.myfamily.com>
Reply-To: <unsubscribe.nbrc8744.000001.1048576.0.0@unsubscribe.myfamily.com>
From: "Ancestry Special Offer" <newsletter@Reply.MyFamilyInc.com>
To: "Mailshell User" <nospam@mailshell.com>
Subject: Connect with your ancestors online
Date: Wed, 08 Jan 2003 07:11:15 -0000

Connect with your ancestors online. Join Ancestry.com
...
Всё ниже со слова Connect является заголовком, или по крайней мере, не нуждается в обработки по IP.

Вот ваш предложенный код:

#!/usr/bin/perl
use Socket;

my $file = './mail/111';
my @ips;
open(FILE,"<$file");
while(<FILE>){
if ( /(\d+\.\d+\.\d+\.\d+)/  ){ # Первый алгоритм
# if ( /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/  ){ # Второй алгоритм
   my $ip = $1;
   @ips = push(@ips,$ip); #для того чтобы поместить айпишник в масив ips(если нужно)
   print "$ip\n"; # для того чтобы вывести его
   $ip = inet_aton($ip);
   $name  = gethostbyaddr($ip, AF_INET); # для того чтобы вернуть его доменое имя
}
}perl

При первом алгоритме имеем такой вывод:

71.129.195.163
63.92.90.192
10.6.8.151
8744.000001.1048576.0
8744.000001.1048576.0

При втором алгоритме имеем следующий вывод:

71
63
10

Вот из-за наличия таких "противных" строк как

Reply-To: <unsubscribe.nbrc8744.000001.1048576.0.0@unsubscribe.myfamily.com>

Первый алгоритм не до конца эффективен, так как нужно строго указать, что цифр может быть НЕ менее 1, но и не более 3.

Второй алгоритм, почему-то, выделяет прочто первую циру каждого IP-шника, хотя отфильтровует IP верно.

>Ну и почитайте книжку по регулярным выражениям.

Подскажите пожалуйста сею книжку, а лучше и url на неё. Я составлял алгоритм, основываясь на этом http://www.opennet.me/docs/RUS/bash_scripting_guide/c11895.h...

P.S. Чувствую тему уже нужно переносить в раздел PERL, но если кто то уверен, что с текущей задачей можно справиться средствами Bash, пожалуйста, предлогайте свои решения :)

Напоминаю папку с письмами,что бы проверить как скрипт должен работать в реальных условиях, можно скачать тут http://ILYA.pp.ua/m.7z


"Bash Скрипт обработка писем или текстовых файлов"
Отправлено L0n3R4ng3r , 18-Июл-10 01:29 
используйте регексп (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) для определения айпишников:

вот файл с письмом :
$ cat qwe
Received: (qmail 29944 invoked from network); 8 Jan 2003 07:10:33 -0000
Received: from dev212.mailshell.com (HELO mailshell.com) (71.129.195.163)
  by dev50.mailshell.com with SMTP; 8 Jan 2003 07:10:33 -0000
Received: (qmail 26211 invoked by uid 99); 8 Jan 2003 07:10:33 -0000
Message-ID: <20030108071033.15907.qmail@mailshell.com>
Received: (qmail 13669 invoked from network); 8 Jan 2003 07:10:31 -0000
Received: from unknown (HELO anclsmtp03.myfamily.com) (63.92.90.192)
  by www.mailshell.com with SMTP; 8 Jan 2003 07:10:31 -0000
Received: from ancnews01 (10.6.8.151) by anclsmtp03.myfamily.com (LSMTP for Windows NT v1.1b) with SMTP id <22.00312C4E@anclsmtp03.myfamily.com>; Wed, 8 Jan 2003 0:11:17 -0700
X-Sender: <unsubscribe.nbrc8744.000001.1048576.0.0@unsubscribe.myfamily.com>
Reply-To: <unsubscribe.nbrc8744.000001.1048576.0.0@unsubscribe.myfamily.com>
From: "Ancestry Special Offer" <newsletter@Reply.MyFamilyInc.com>
To: "Mailshell User" <nospam@mailshell.com>
Subject: Connect with your ancestors online
Date: Wed, 08 Jan 2003 07:11:15 -0000

Connect with your ancestors online. Join Ancestry.com

вот вывод:
$ cat qwe  | perl -ne 'if (/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) { print "$1.$2.$3.$4\n" }'
71.129.195.163
63.92.90.192
10.6.8.151