Мысль дня

Ты никогда не решишь проблему, если будешь думать так же, как те, кто её создал.

© Альберт Эйнштейн

Пересылка всей почты другому пользователю

Дело было во FreeBSD. Настроил я sendmail, а заодно переадресацию почты одному пользователю. Все новые письма пересылаются, как положено, а вот старые, которые лежат в /var/mail/*, так там и лежат. И вот захотелось получить эти письма так же, как и новые: удалённо почтовым клиентом через IMAP.

Чувствуя пятой точкой, что должен быть до безобразия простой способ это сделать, я обратился на тематический форум, где помочь мне не смогли. Видимо действительно такого способа нет. Что ж, пришлось изобретать велосипед. Собственно, вот и он:

  1. #!/bin/sh
  2.  
  3. my_sendmail="/usr/sbin/sendmail -v username@mail.server.xx"
  4. my_file="/var/mail/www"
  5. my_awk="/usr/bin/awk"
  6. my_cat="/bin/cat" 
  7. my_sed="/usr/bin/sed -n"
  8. my_wc="/usr/bin/wc -l"
  9.  
  10. while read str
  11. do
  12.   i=`expr $str - 1`  
  13.   if [ ${i} -gt 0 ]; then
  14.     ${my_sed} "${j},${i}p" ${my_file} | ${my_sendmail} 
  15.   fi
  16.   j="${str}"
  17. done <<EOF 
  18. `${my_cat} -n ${my_file} | ${my_awk} '/From / {print $1}'`
  19. EOF
  20.  
  21. i=`${my_cat} -n ${my_file} | ${my_wc}`
  22. ${my_sed} "${j},${i}p" ${my_file} | ${my_sendmail}

А теперь по порядку.

В четвёртой строчке указана переменная, в которой хранится путь к файлу с письмами. В данном случае это почтовый ящик пользователя www. Именно эти письма мы и будем пересылать.

В третьей строчке устанавливается перменная, которая содержит в себе путь к исполняемому файлу sendmail с опциями. В качестве опций указан email, на который следует переслать все письма. Опция -v указана, чтобы не было скучно смотреть в пустую консоль. :) Впрочем, если вам не интересно работает sendmail или уже висит, то можете -v не указывать. Опция -t не указана, но если вам потребуется переслать письма туда же, куда они предназначались изначально, то следует указать -t (email в таком случае можно не указывать).

В восемнадцатой строке мы выводим содержимое файла с письмами с нумерацией строк. Затем передаём результат по конвейеру в awk, который оставляет только номера строк, в которых присутсвует «From » (без кавычек и с пробелом на конце). Такими строками начинаются все письма. Результат работы awk передаётся в цикл while (строка 10) для дальнейшей обработки.

С десятой строки начинается условие, которое выполняется для данных, взятых  из строки 18. Код написан «задом–наперёд» не просто так. Таким хитрым образом мы заставляем цикл while работать в контексте основной программы. Исполняется while в другой дочерней оболочке и все данные, которые в нём будут сгенерированы, не будут доступны основной программе. Так как они нам всё–таки понадобятся, мы и используем heredoc–синтаксис, ну и придаём нашему скрипту  немного задом–наперёдности. :) Итак, в цикл while передаётся номер строки.

Далее в строке 12 номер полученной строки уменьшается на еденицу и присваивается переменной i.

В строке 13 мы проверяем не равен–ли номер строки нулю. Это важно! Так–как на предыдущем шаге мы уменьшаем номер, у нас вполне может оказаться в обработке нулевая строка, что недопустимо.

На четырнадцатом шаге мы берём из файла с письмами диапазон строк, сооответствующий одному письму. Диапазон представлен номером конечной строки i, который мы только что определили, и номером начальной строки j, который мы определили на предыдущей итерации цикла while. Далее этот диапазон передётся по конвейеру сендмейлу, который их тут же отсылает в виде письма.

В шестнадцатой строке мы присваиваем перменной j номер начальной строки, который будет использован при следующей итерации цикла while.

В строке 21 мы высняем номер строк в файле с письмами. Это нужно, чтобы было возможно указать диапазон строк для письма находящегося в конце файла.

В 22–й строке мы делаем то же саме, что и в 14–й, но для последнего письма.

Логика работы.

После запуска программы, с помощью конструкции cat -n /var/mail/www, выводится содержимое файла с письмами с пронумерованными строками. Этот текст обрабатывается конструкцией awk '/From / {print $1}', в результате чего мы получаем номера строк с текстом "From " (без кавычек и с пробелом на конце). С такой строки начинается каждое письмо. Список номеров строк передаётся циклу while, условие работы которого задано конструкцией read str. Это означет, что список номеров строк будет читаться построчно по одному номеру за раз, который будет присвоен перменной str.

На первом шаге цикла while переменная str будет равна 1. Что означает, что письмо начинается с первой строки файла /var/mail/www. Это конечно хорошо, но мы не знаем где кончается письмо. Для этого нужно прогнать цикл while ещё раз и найти номер строки, с которой начинается следующее письмо и отнять от него еденицу, что мы и делаем в самом начале цикла while с помощью конструкции i=`expr $str - 1`. Так-как при первой итерации while конечная строка первого письма нам не известна, мы не можем задать диапазон строк, в пределах которых лежит первое письмо. Поэтому, с помощью условия if [ ${i} -gt 0 ], мы отсекаем попытку использовать данные первой итерации для разбора файла с письмами. Это возможно, так–как при первом запуске цикла while переменная i была равна еденице, а в самом начале цикла мы ещё уменьшили на еденицу. В результате условие if [ ${i} -gt 0 ] не выполнится. Зато выполнится следующая за ним конструкция j="${str}", которая присвоит переменной j номер первой строки, еденицу.

На втором шаге цикла while переменная str будет равна номеру, соотвествующему началу второго письма. Далее он будет понижен на еденицу конструкцией i=`expr $str - 1`, чтобы найти номер последней строки предыдущего письма. Теперь условие if [ ${i} -gt 0 ] выполнится, так–как переменная i, содержащая номер последней строки, будет больше нуля. Теперь в дело вступит конструкция sed "${j},${i}p" /var/mail/www, которая выведет диапазон строк между строкой номер j (началом письма) и строкой номер i (концом письма) и передаст его программе sendmail на отправку. Напомню, что значение переменной j мы определили на предыдущем шаге.

Те же действия, что и на втором шаге цикла while, повторятся для всех найденных писем, кроме последнего.

При достижении номера первой строки последнего письма, происходит последняя итерация цикла while, на котрой отправляется предпоследнее письмо из файла /var/mail/www. По концовке цикла у нас есть лишь номер первой строки последнего письма, который хранится в переменной j. Чтобы получить доступ к этой переменной вне цикла while и нужна была задом–наперёдная структура программы. :) Осталось получить номер последней строки последнего письма. Делается это с помощью конструкции i=`cat -n /var/mail/www | wc -l`. Далее конструкция sed "${j},${i}p" /var/mail/www выводит диапазон строк между строкой номер j (началом письма) и строкой номер i (концом письма) и передаёт его программе sendmail на отправку.

Вот и всё. Все письма отправлены.

Комментарии

7 лет назад
Спасибо за статью и за прекрасное описание скрипта! Очень помогло!

Архив

  1. 2022
    1. август
      1. Сайт восстановил работу
  2. 2021
    1. январь
      1. Kubntu Linux Opera: не работает видео
      2. Не обновляется FreeBSD со старой версии, ошибка «Cowardly»
  3. 2015
    1. сентябрь
      1. Ворона позирует
      2. Как сделать новость из ничего
    2. август
      1. Моё первое селфи
      2. Спам от Майкрософта
    3. июнь
      1. 1000
      2. Сельдерей
    4. май
      1. Сирень зацвела
      2. Ночное солнце
    5. апрель
      1. Ить-ить-ить-ить
    6. январь
      1. Разрыв VPN-соединения при нагрузке
  4. 2014
    1. декабрь
      1. Суровый холостяцкий смайл
    2. ноябрь
      1. Перечень IP–адресов в IPFW
      2. Длина строки правила IPFW во FreeBSD
    3. октябрь
      1. Свет в конце тоннеля
      2. Огоньки
    4. сентябрь
      1. Попал под раздачу
      2. Собираю чемодан
      3. Чьи–то уши торчат над холмом
      4. Увеличение свободного места на телефоне LG P500 Optimus One
      5. Места нет, но место есть
      6. Пластиковая Африка
    5. август
      1. Кошка в ванной
      2. В PHP функция возвращает NULL вместо данных
      3. В Оперу вернулись закладки!
      4. Убираем рамки вокруг экрана
      5. Загадочный дом
    6. июль
      1. Божьи коровы и прочие твари
      2. Человек собаке друг
    7. июнь
      1. Котоворот
      2. Древесная живность
      3. Шампунь
    8. апрель
      1. Еда
      2. Смайл
      3. Одуванчики
      4. Шашлычная история
      5. Кровавая Луна
      6. Старый пень
      7. Бриллиант
    9. март
      1. Лисапет наносит ответный удар
      2. Весна пришла или Лисапет 2
      3. Лисапет
      4. Запах весны
    10. январь
      1. Восстановление данных и лечение HDD с помощью dd во FreeBSD
      2. Новогодняя ёлка 2014
  5. 2013
    1. декабрь
      1. Ледяные короны
      2. Луна
    2. ноябрь
      1. Тарас Шевченко - І виріс я на чужині
      2. Увеличение раздела диска во FreeBSD
      3. Одна особенность работы freebsd-update
    3. октябрь
      1. Обзор телефона LG P500 Optimus One
      2. Призрачная трава
    4. сентябрь
      1. Подарок
      2. Мокрая, как мышь
      3. Пластиковое нашествие
      4. Использование переменных в шаблоне REGEXP
    5. август
      1. Файл конфигурации MPlayer
      2. Микширование аудиоканалов в MPlayer
      3. Спамеры тоже люди
      4. Распятый мексиканец
      5. Подсолнуховое море
      6. Подложили свинью
      7. Глобальное обновление
    6. апрель
      1. Завтрак
    7. март
      1. Пересылка всей почты другому пользователю
    8. январь
      1. Задолбали ссылки
      2. Xerox Phaser 6000 против Linux x86_64
  6. 2012
    1. декабрь
      1. Изогнутый айфон
    2. октябрь
      1. Собака бывает кусачей
    3. июнь
      1. Поддержка Monkey's Audio в Linux
      2. Поддержка чересстрочного VC–1 в 64–битном линуксе
      3. Моя кошка ловит мушку
      4. Диапазон IP–адресов в IPFW
    4. май
      1. Задушила меня жаба
    5. февраль
      1. Как закрыть и открыть порты во FreeBSD
    6. январь
      1. Обмен данными между скриптами shell и PHP
  7. 2011
    1. декабрь
      1. Пасхальное яйцо в Muon
    2. ноябрь
      1. Windows XP и NFS
      2. От природы не уйдёшь
    3. октябрь
      1. Swappiness
      2. Бодания с Ubuntu 11.10
      3. Подпишись, не будь упырём!
      4. Установка Ubuntu на RAID 0
      5. Кодинг на сон грядущий
    4. сентябрь
      1. Аську! Больше асек!
      2. Разбитое сердце
      3. Привет из параллельной вселенной
      4. Карточный домик
    5. август
      1. Обзор ноутбука ASUS 1215B
    6. июль
      1. Работает–ли компьютер без видеокарты?
    7. июнь
      1. Частушка на злободневную тему
    8. май
      1. Как–то в прошлой жизни…
    9. март
      1. 8 марта
      2. Планшеты
      3. Цветы
  8. 2010
    1. декабрь
      1. Типа динамическая маршрутизация
    2. ноябрь
      1. Закрытые порты или бодания с FreeBSD
      2. Мой новый старый комп
      3. Глюк с кодировкой в MySQL
      4. Ёжик в тумане
    3. август
      1. Кукурузное счастье
    4. май
      1. День победы 2010
      2. Не пора–ли менять браузер?
      3. Оптимизация дисковой системы в Linux
  9. 2009
    1. ноябрь
      1. Перенос системы на другой жёсткий диск
    2. август
      1. Выбор HTML–редактора под линукс
      2. Сходим в оперу?
      3. Линукс
      4. 4:00
    3. июль
      1. Семантичеcкие URL
      2. Браузеры под раздачей
      3. Графика
      4. Достало!
      5. Где–то там море
      6. С чего всё началось
      7. Начало

Поддержка проекта

Поделиться

Комментировать