В данном разделе находится общая информация.
В данном разделе находятся примеры различных Linux shell скриптов.
В данном разделе находятся примеры различных скриптов на WSH.
В данном разделе находятся материалы по разным темам.

Правильный CSS!

Для корректного отображения страницы, рекомендуется использовать браузер поддерживающий JavaScript.

Для навигации пользуйтесь боковым меню и кнопками "Описание" и "Подробно".

Linux cкрипт findmail.sh для трассировки письма по лог-файлам Postfix

Cкрипт findmail.pl и findmail.sh разработан для тассировки письма (поиска) в лог-файле Postfix.

Основные возможности:

  • findmail.sh - bash версия,
    findmail.pl - perl версия;
  • Принудительный выбор лог-файла (если не указан, то по умолчанию /var/log/mail);
  • Многоуровневая трассировка письма (например, при наличии коннектора amavisd-new) или принудительный выбор релея;
  • Поиск по дате и e-mail адресу получателя или отправителя.
mail:/home/postadmin # findmail.sh -d "Nov 18 15" -t user@mydomain.com -r all
=============================================================
 Фильтрация лога. Это может занять некоторое время... Готово
=============================================================
==============================
 Trace mail started with keys:
==============================
type=t
date=Nov 18 15
e-mail=user@mydomain.com
logfile=/var/log/mail-20091119.gz
relay=
------------------
 Found mail id's:
------------------
60D39F8F39
0B394F8F5A
E8D1FF8F49
--------------------------------
 Trace mail with id: 60D39F8F39
--------------------------------
Nov 18 15:12:12 mail postfix/smtpd[31049]: 60D39F8F39: client=guard.mydomain.local[10.1.1.9]
Nov 18 15:12:12 mail postfix/cleanup[30110]: 60D39F8F39: message-id=<20091118121212.2C6BC1A22AC@guard.mydomain.com>
Nov 18 15:12:12 mail postfix/qmgr[8799]: 60D39F8F39: from=<guard@mydomain.com>, size=1165, nrcpt=1 (queue active)
Nov 18 15:12:13 mail postfix/smtp[30201]: 60D39F8F39: to=<user@mydomain.com>, relay=127.0.0.1[127.0.0.1]:10024, delay=0.8, delays=0.02/0/0/0.77, dsn=2.0.0, status=sent (250 2.0.0 Ok, id=26709-12, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 0B394F8F5A)
Nov 18 15:12:13 mail postfix/qmgr[8799]: 60D39F8F39: removed
--------------------------------
 Trace mail with id: 0B394F8F5A
--------------------------------
Nov 18 15:12:13 mail postfix/smtpd[31068]: 0B394F8F5A: client=localhost[127.0.0.1]
Nov 18 15:12:13 mail postfix/cleanup[30110]: 0B394F8F5A: message-id=<20091118121212.2C6BC1A22AC@guard.mydomain.com>
Nov 18 15:12:13 mail postfix/qmgr[8799]: 0B394F8F5A: from=<guard@mydomain.com>, size=1213, nrcpt=1 (queue active)
Nov 18 15:12:13 mail postfix/smtp[30819]: 0B394F8F5A: to=<user@mydomain.com>, relay=10.1.1.8[10.1.1.8]:25, delay=0.58, delays=0.14/0/0/0.44, dsn=2.6.0, status=sent (250 2.6.0  <20091118121212.2C6BC1A22AC@guard.mydomain.com> Queued mail for delivery)
Nov 18 15:12:13 mail postfix/qmgr[8799]: 0B394F8F5A: removed
--------------------------------
 Trace mail with id: E8D1FF8F49
--------------------------------
Nov 18 15:20:01 mail postfix/pickup[31098]: E8D1FF8F49: uid=0 from=<root>
Nov 18 15:20:01 mail postfix/cleanup[308]: E8D1FF8F49: message-id=<20091118122001.E8D1FF8F49@mail.mydomain.com>
Nov 18 15:20:01 mail postfix/qmgr[8799]: E8D1FF8F49: from=<root@mydomain.com>, size=611, nrcpt=1 (queue active)
Nov 18 15:20:02 mail postfix/smtp[336]: E8D1FF8F49: to=<user@mydomain.com>, orig_to=<root>, relay=10.1.1.8[10.1.1.8]:25, delay=0.45, delays=0.12/0/0/0.32, dsn=2.6.0, status=sent (250 2.6.0  <20091118122001.E8D1FF8F49@mail.mydomain.com> Queued mail for delivery)
Nov 18 15:20:02 mail postfix/qmgr[8799]: E8D1FF8F49: removed
======================
 Trace time (sec): 18
======================
mail:/home/postadmin #

Пример cкрипта findmail.pl и findmail.sh для трассировки письма по лог-файлам Postfix

(Скачать файл можно будет здесь. ЗЫ Не тыкать! Жать правой кнопкой: сохранить ссылку как...)

Условия:

Используй: findmail.pl -f|-t e-mail [-d date] [-l logfile] [-r relay]
  • -t|-f - поиск по e-mail получателя|отправителя (формат: sample@sample.ru)
  • -d - дата (формат:"Mar 10 12:00:00")
  • -l - логфайл (формат:/var/log/mail), по умолчанию /var/log/mail
  • -r - релей (формат:192.168.1.1|all), по умолчанию 127.0.0.1 (с ключем -f релей игнорируется)
  • -h - показать справку
Обязательные параметры: e-mail отправителя или получателя.
Необязательные параметры: дата в формате используемом в лог-файле (например "Mar 10 12:00:00" или "Mar 10 12" и т.д. обязательно в кавычках), логфайл и релей
Пример: findmail.pl -d "Nov 18 15" -t user@mydomain.com -l /var/log/mail -r all

Текст findmail.pl:

#!/usr/bin/perl -w
#
#Copyright 2010 Konstantin Nadezhdin (nk_rec AT mail DOT ru)
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

use strict;
my($nexts,$ftf,$fd,$fe,$fl,$fltype,$fr,$fn) = ("","","","","/var/log/mail","","all",0);
my($GREP_BIN) = "/usr/bin/grep";
my($tftStr,$OutStr,$Fld,$ID,$IDn,$c_d_expr,$c_d_expr1,$c_d_expr2,$c_d_time,$c_d_time_sek,$ID_COUNT_NOQUEUE);
my($starttime,$worktime) = 0;
my(%ID_COUNT,%c_d_expr,%FILTERED_LOG);
foreach (@ARGV) {
	if ($_ eq "-t") {
		$nexts = "ft";
	} elsif ($_ eq "-f") {
		$nexts = "ff";
	} elsif ($_ eq "-d") {
		$nexts = "fd";
	} elsif ($_ eq "-l") {
		$nexts = "fl";
	} elsif ($_ eq "-r") {
		$nexts = "fr";
	} elsif ($_ eq "-n") {
		$fn = 1;
	} elsif ($_ eq "-h") {
		die "Используй: -f|-t e-mail [-d date] [-l logfile] [-r relay] [-n] -h
			\t-f|-t - поиск по e-mail получателя|отправителя (формат: sample\@sample.ru);
			\t-d - дата (формат:\"Mar 10 12:00:00\");
			\t-l - логфайл (формат:/var/log/mail), по умолчанию /var/log/mail;
			\t-r - релей (формат:192.168.1.1|mx.host.name|all), по умолчанию all (с ключем -f релей игнорируется);
			\t-n - только NOQUEUE;
			\t-h - показать справку.\n";
	} else {
		if ($nexts eq "fd") {
			($fd = $_) =~ s/ /  \?/;
		} elsif ($nexts eq "ft") {
			$fe = $_; $ftf = "t";
		} elsif ($nexts eq "ff") {
			$fe = $_; $ftf = "f";
		} elsif ($nexts eq "fl") {
			$fl = $_;
		} elsif ($nexts eq "fr") {
			$fr = $_;
		}
		$nexts = "";
	}
}

($fe eq "") && die "Ошибка: e-mail не указан!\n";
if ($fl eq "") {
	print "Не указан лог, использую по умолчанию!\n";
	$fl = "/var/log/mail";
}
(-e $fl) || die "Ошибка, $fl несуществует или нулевой!\n";

($fltype = $fl) =~ s/^.*\.//;
if ($fltype eq "gz") {
	$GREP_BIN="/usr/bin/zgrep";
} elsif ($fltype eq "bz2") {
	$GREP_BIN="/usr/bin/bzgrep";
}
if ($fr eq "all" or $ftf eq "f") {
	$fr = "";
}

if ($ftf eq "t") {
	if ($fn) {
		$tftStr = "to=<$fe> proto";
	} else {
		$tftStr = "to=<$fe>, relay=$fr";
	}
} elsif ($ftf eq "f") {
	if ($fn) {
		$tftStr = "from=<$fe> to=";
	} else {
		$tftStr = "from=<$fe>, size=";
	}
}

$OutStr = " Фильтрация лога. Это может занять некоторое время... ";
echo_for("$OutStr     ","=");
print "$OutStr";
$starttime = `date +%s.%N`;
open(LOG,"$GREP_BIN -Ei \"^$fd.* $tftStr\" $fl|") || die "Ошибка $!\n";
while (<LOG>) {
	($Fld = (split(/  ?/))[5]) =~ s/:$//;
	if ($Fld eq "NOQUEUE") {
		$FILTERED_LOG{'NOQUEUE'} .= $_;
		$ID_COUNT_NOQUEUE++;
	} else {
		$ID_COUNT{$Fld}++;
	}
	
}
close(LOG);
$ID = join("|",(keys(%ID_COUNT)));

$ID_COUNT{'NOQUEUE'} = $ID_COUNT_NOQUEUE if (defined($FILTERED_LOG{'NOQUEUE'}));
if ($ID eq "" and ! defined($ID_COUNT{'NOQUEUE'})) { print "Ничего не найдено.\n"; die "$!\n"; }
print "похоже, что-то есть... ";
unless ($ID eq "") {
	open(LOG,"$GREP_BIN -Ei \"^$fd.* ($ID):\" $fl|") || die "Ошибка $!\n";
	while (<LOG>) {
		($Fld = (split(/  ?/))[5]) =~ s/:$//;
		if (defined($ID_COUNT{$Fld})) {
			$FILTERED_LOG{$Fld} .= $_;
		}
	}
	close(LOG);
}

print "Готово\n";
echo_for("$OutStr       ","=");
echo_for2(" Trace mail started with keys:","=");
print "type=$ftf\ndate=$fd\ne-mail=$fe\nlogfile=$fl\nrelay=$fr\n";

foreach (keys(%FILTERED_LOG)) {
	$OutStr = " Trace mail with id: $_ ";
	echo_for2("$OutStr","-");
	print "$FILTERED_LOG{$_}\n";
}

echo_for2(" Traced mail id's: ","-");
foreach (keys(%ID_COUNT)) {
        printf("%-10s : %d\n",$_,$ID_COUNT{$_});
}
$worktime = `date -d "-$starttime seconds" "+%s.%N"`;
chomp($worktime);
echo_for2(" Trace time (sec): $worktime ","=");

sub echo_for {
	my($a,$b) = @_;
	my($strOut) = "";
	$strOut = $b x length($a);
	print "$strOut\n";
}

sub echo_for2 {
	my($a,$b) = @_;
	echo_for($a,$b);
	print "$a\n";
	echo_for($a,$b);
}

	

Текст findmail.sh:

#!/bin/bash
#
#Copyright 2010 Konstantin Nadezhdin (nk_rec AT mail DOT ru)
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

nexts=""
ftf=""
fd=""
fe=""
fl="/var/log/mail"
fr="127.0.0.1"
for i in "$@"; do
	case $i in
		-t) nexts="ft";;
		-f) nexts="ff";;
		-d) nexts="fd";;
		-l) nexts="fl";;
		-r) nexts="fr";;
		-h) echo -e "Используй: $0 (-t e-mail | -f e-mail) -d date [-l logfile] [-r relay]\
			\n\t-t|-f - поиск по e-mail получателя|отправителя (формат: sample@sample.ru)\
			\n\t-d - дата (формат:\"Mar 10 12:00:00\")\
			\n\t-l - логфайл (формат:/var/log/mail), по умолчанию /var/log/mail\
			\n\t-r - релей (формат:192.168.1.1|all), по умолчанию 127.0.0.1 (с ключем -f релей игнорируется)\
			\n\t-h - показать справку"; exit 0;;
		*)
			case $nexts in
				fd) fd="${i/ /  ?}"; nexts="";;
				ft) fe="$i"; ftf="t"; nexts="";;
				ff) fe="$i"; ftf="f"; nexts="";;
				fl) fl="$i"; nexts="";;
				fr) fr="$i"; nexts="";;
			esac
		;;
	esac
done

test "$fd" || { echo "Ошибка: дата не указана!"; $0 -h; exit 1; }
test "$fe" || { echo "Ошибка: e-mail не указан!"; $0 -h; exit 1; }
test -s "$fl" || { echo "Логфайл $fl несуществует или нулевой!"; exit 1; }
fltype="${fl##*.}"
case $fltype in
        gz) GREP_BIN="/usr/bin/zgrep";;
        bz2) GREP_BIN="/usr/bin/bzgrep";;
        *) GREP_BIN="/usr/bin/grep";;
esac
test "$fr" = "all" -o "$ftf" = "f" && fr=""

get_logs () {
	#c_d=$($GREP_BIN "$1.* postfix/smtpd.* $2: client=" $3)
	c_d="$(echo "$3" | grep -E "$1.* postfix/(smtpd.* $2: client|pickup.* $2: uid)=")"
	#test "$c_d" = "" && c_d=$($GREP_BIN "$1.* postfix/pickup.* $2: uid=" $3)
	test "$c_d" || { echo "Ошибка. Переменная c_d пуста. Попробуй задать другой фильтр."; exit 1; }
	#echo "c_d=$c_d"
	c_d_expr2="$(echo "$c_d" | awk 'sub(".$","",$3) {print $1"  ?"$2" "$3}'). .* $2:"
	#echo "c_d_expr2=$c_d_expr2"
	c_d_time=$(echo "$c_d" | awk '{print $3}')
	#echo "c_d_time=$c_d_time"
	c_d_time_sek=$(echo "$c_d_time" | sed "s/.$/\./")
	#echo "c_d_time_sek=$c_d_time_sek"
	c_d_expr1=$(echo "$c_d" | sed -e "s/ $2: client=/ (connect|disconnect) from /" -e "s/\[/\./g" -e "s/\]/\./g" -e "s/ $c_d_time / $c_d_time_sek /")
	#echo "c_d_expr1=$c_d_expr1"
	#$GREP_BIN -E "^($c_d_expr1|$c_d_expr2)" $3
	echo "$3" | grep -E "^($c_d_expr1|$c_d_expr2)"
}

echo_for () {
	lOutStrmax=${#1}
	for ((lOutStr=0; lOutStr<lOutStrmax; lOutStr++)); do echo -n "$2"; done
	echo ""
}

echo_for2 () {
	echo_for "$1" "$2"
	echo "$1"
	echo_for "$1" "$2"
}

case $ftf in
	t) tftStr="to=<$fe>,.* relay=$fr";;
	f) tftStr="from=<$fe>,.* size=";;
esac

OutStr=" Фильтрация лога. Это может занять некоторое время... " 
echo_for "$OutStr       " "="
echo -n "$OutStr"
starttime=$(date +%s.%N)
ID="$($GREP_BIN -E "^$fd.* $tftStr" $fl | awk '{print $6}' | sort -u | sed ':a; s/://g; /$/N; s/\n/ /; ta')"
test "$ID" || { echo -e "Ошибка\n\tФильтр вернул пустой массив (попробуй указать другой фильтр)."; exit 1; }
FILTERED_ID="${ID// /|}"
FILTERED_LOG="$($GREP_BIN -E "^$fd.*($FILTERED_ID):" $fl)"
echo "Готово"
echo_for "$OutStr       " "="
echo_for2 " Trace mail started with keys:" "="
echo -e "type=$ftf\ndate=$fd\ne-mail=$fe\nlogfile=$fl\nrelay=$fr"
echo_for2 " Found mail id's: " "-"
echo "$ID" | sed 's/ /\n/g'

for i in $ID
do
	#if [ "$mailid1" = "" ]; then
		mailidi=$i
	#else
                #mailidi=$i" "$mailid1
	#fi
	#echo_for2 " All id's to trace for: $i " "-"
	#echo "$mailidi"
	OutStr=" Trace mail with id: $i "
	for j in $mailidi
	do
		echo_for2 "$OutStr" "-"
		get_logs "$fd" "$j" "$FILTERED_LOG"
	done
done
worktime=$(date -d "-$starttime seconds" "+%s.%N")
echo_for2 " Trace time (sec): $worktime " "="

	

Что нового в этой версии:

Версия 1.3 (Срд Июн 2 2010):
- Переписан на perl;
- Оптимизация bash версии.
Версия 1.2 (Пнд Ноя 30 2009):
- Оптимизирован код для повышения быстродействия, добавлена предварительная фильтрация лога.
Версия 1.1 (Срд Ноя 18 2009):
- Добавлена возможность обрабатывать сжатые логи (gz и bz2);
- Добавлен поиск по адресу отправителя.
Версия 1.0:
- Первый релиз.

Rambler's Top100

Yandex.Metrika

Page modification: Птн Сен 10 16:48:10 MSD 2010
Используется Quanta+ 3.5.10 Under the GPL v2 license.