Разные, на мой взгляд, интересные замечания, связанные с компьютерами в частности и техникой вообще.

Показаны сообщения с ярлыком bash. Показать все сообщения
Показаны сообщения с ярлыком bash. Показать все сообщения

пятница, 4 июня 2010 г.

Настройка атоматического выбора wi-fi сети в Debian.

Есть у меня одна замечательная вещь - Asus EeePC. И, так как тут имеется wi-fi карта, не пользоваться услугами беспроводной связи просто грех. Но хорошо, когда сеть одна. А что, если их много и надо в одном месте включать одну, в другом другую? И при этом всякие графические монструозные комбайны ставить не хочется. Как быть? Настроить имеющиеся в Debian'е инструменты работы с сетью. Это на самом деле намного проще, чем может показаться на первый взгляд.
Управление сетевыми интерфейсами осуществляется в Debian'е через файл /etc/network/interfaces и скрипт /etc/init.d/networking. Для нас важен файл настроек. Если заглянуть в его man, то можно найти замечательный параметр mapping. Эта опция даёт возможность создавать разные логические интерфейсы на одном физическом и автоматически выбирать нужный по определённым параметрам. Проще говоря - что-то типа профилей. Для выбора надо набросать небольшой скриптик и прописать условия.
Итак, к делу.
Условие определения логического интерфейса могут быть любые. Мне лично удобно по mac-адресу(логичнее, конечно, кажется по SSID, но мне этот вариант не подходит, потому что на всех, настроенных мной точках, я выставляю опцию SSID Broadcast в off, поэтому увидеть его стандартными средствами, не подключившись проблематично, но если у вас не так, то разумеется определение профиля по SSID более правильный выбор). Логика работы проста - при поднятии интерфейса, система сканирует сеть, смотрит, какая из знакомых ей точек доступна и подключается к ней. Основную работу за нас будет делать небольшой скрипт. Примеры таких скриптов можно глянуть в /usr/share/doc/ifupdown/examples/ . Там же лежат примеры настройки файла interfaces. У меня скрипт получился такой:

#!/bin/sh
#
# Auto wi-fi choise.

iface="$1"
ifconfig=$(which ifconfig)
iwlist=$(which iwlist)
which=""

# Проверка на случай, если wi-fi карта выключена.
if [ ! "$(grep $iface /proc/net/dev)" ]; then exit 1; fi

# Без этого не получится просканировать сеть.
$ifconfig $iface up

# Собственно выбор.
while read mac scheme; do
    if [ "$which" ]; then continue; fi
    if [ "$($iwlist $iface ap | grep $mac)" ]; then which="$scheme"; fi
done

# Передача выбора системным скриптам и выход.
if [ "$which" ]; then echo $which; exit 0; fi
exit 1

Как можно заметить, несмотря на простоту, в скрипте есть несколько особенностей. Первая - ему по умолчанию в качестве первого аргумента передаётся имя интерфейса. Вторая - он читает построчно заданные в настройках параметры. Третья - он должен вернуть выбранное логическое имя интерфейса и код выхода(0 - всё хорошо, работаем, 1 - ошибка, выходим). Если первое и последнее - понятно, то второе требует небольшого пояснения. Скрипту передаются параметры, заданные в interfaces. Последним параметром обязательно должно быть имя логического интерфейса. И всё, что делает скрипт, в конечном счёте направлено на то, чтобы это имя вернуть на stdout. Как видно, в моём случае я сканирую воздух, и, если попадается знакомый mac, тут же выбираю соответствующее ему имя. Если знакомых нет, разумеется подключение прерывается. Маки и имена указаны в interfaces. Для тех, кто будет использовать выборку по SSID, надо будет сделать что-то типа iwlist $iface scanning | grep $ssid.
И наконец, запись в interfaces:

mapping ath0
    script /usr/local/sbin/awfc.sh
    map 11:22:33:44:55:66    ath0-home
    map AA:BB:CC:DD:EE:FF    ath0-tmp

allow-hotplug ath0
# Домашняя сетка
iface ath0-home inet dhcp
    wireless-essid        HomeNet
    wpa-ssid        HomeNet
    wpa-psk            *********
# моё любимое кафе с wi-fi
iface ath0-tmp inet dhcp
    wireless-essid        TMPNet

Я для примера показал две точки, но их на самом деле может быть сколько угодно. Главное соблюдать формат записи - map mac-адрес логическое_имя. Разумеется, параметры для каждой из точек могут совершенно любыми.
И последний штрих. Дело в том, что по умолчанию при загрузке /etc/init.d/networking стартует достаточно рано относительно других сервисов. Оно понятное дело нужно, когда у меня сервер со всякими sshd, apache и прочими радостями. Но на нетбуке это совершенно лишнее. А из-за такой "спешки" не успевают подгрузиться все нужные для работы выбирающего скрипта части. А именно, не инициализировался до конца интерфейс, поэтому команда iwlist не возвращала ожидаемого результата. Я решил это просто - двумя командами перенёс загрузку сети с ранних этапов на стандартные, вместе с основными частями системы:

# update-rc.d -f networking remove
# update-rc.d networking defaults

Всё. При загрузке, если я нахожусь в зоне действия знакомой сети, нетбук автоматом к ней подключится. Если я не выключал нетбук и перешёл от одной знакомой сети к другой, достаточно рестартануть сеть и всё будет отлично.
Именно за такие простые и удобные вещи я и люблю Linux вообще и Debian в частности.

четверг, 18 марта 2010 г.

Дискриминация по национальному признаку или баним страны.

Так получилось, что понадобилось прикрыть доступ к серверу из некоторых стран. Понимаю, что кровавая гебня и всё такое, но задача есть, надо сделать.
Вот здесь находим архивчик с базой IP-адресов и их национальной принадлежностью. Далее за нас работает небольшой скрипт:
#!/bin/bash
#
TMPDIR=/tmp/geoiptban
IP_BBASE=$TMPDIR/bbase.csv
IP_EBASE=$TMPDIR/ebase.csv
DB_ZIP=$TMPDIR
PERL=/usr/bin/perl
FILE_BCOUNTRY=$1
COUNTRY_DB_URL=http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip
mkdir -p $TMPDIR
# Стягиваем и распаковываем базу айпишников.
wget -q -O $DB_ZIP $COUNTRY_DB_URL
unzip -p $DB_ZIP > $IP_BBASE
# Убираем лишние символы из базы, для простоты обработки.
if [ -e "$IP_BBASE" ]
then
        cp $IP_BBASE $IP_EBASE
        $PERL -pi -e 's/"//g' $IP_EBASE
else
        echo "Source ip-base-file not found."
        exit 0;
fi
# Обработка базы. Форматируем базу сперва в вид диапазонов ip-адресов, а потом в список подсетей.
# Получившиеся подсети скармливаем iptables'у.
if [ -e "$FILE_BCOUNTRY" ]
then
        for country in $(cat ${FILE_BCOUNTRY})
        do
                grep $country $IP_EBASE | awk -F "," '{print $1," - ",$2}' > $TMPDIR/$country.il
                for ((i=1;i<=$(wc -l ${TMPDIR}/${country}.il | awk '{print $1}');i++))
                do
                        ipcalc $(head -n ${i} ${TMPDIR}/${country}.il | tail -n 1) | grep -v deaggregate >> $TMPDIR/$country.nl
                done
        done
        for country_network_list in $(ls ${TMPDIR} | grep nl)
        do
                for ((i=1;i<=$(wc -l ${TMPDIR}/$country_network_list | awk '{print $1}');i++))
                do
                        iptables -t filter -A INPUT -s $(head -n ${i} ${TMPDIR}/$country_network_list | tail -n 1) -j DROP
                done
        done
else
        echo "List of blocked countries not found."
        exit 0;
fi
rm -rf $TMPDIR
Для определения списка стран, которые надо забанить используется файл, в котором просто перечисляются их коды:
[root@gateway ~]# cat country_list
RU US GB
Запускается скрипт очень просто:

[root@gateway ~]# ./geoiptban.sh country_list

вторник, 17 ноября 2009 г.

Запись устанавливаемых зависимостей для пакета в Debian.

Часто приходится ставить софт "на посмотреть". Т.е. поставил, один-два раза запустил и удалил. Вроде бы ничего страшного - apt-get наш спаситель, но нередко бывает, что пакет при установке притягивает за собой толпы библиотек по зависимостям, и при удалении этого пакета все библиотеки остаются в системе. Часть из них, конечно, можно вычистить с помощью apt-get autoremove, но большая часть всё-таки остаётся. Я обычно в таких случаях записывал себе куда-нибудь список пакетов, устанавливаемых с нужным мне софтом и потом сносил его руками. Вот, решил этот процесс немного автоматизировать скриптом. Ничего особенного, просто небольшая экономия времени.

#!/bin/bash
#

INST_BASE=/var/cache/apt/Inst
INST_PROG=/usr/bin/apt-get

# Функция вывода ошибки в случае использования неправильных аргументов
f_argerror() {
    echo "depends_store.sh: Пропущен операнд."
    echo "Попробуйте \"depends_store.sh -h\" для получения более подробного описания."
}

# Функция записи данныхх о зависимостях с проверкой на наличие этих данных.
# Если данные имеются, вызывается функция их вывода.
f_install() {
  if [ -e ${INST_BASE}/${OPTARG} ]
  then
    echo "Данные о зависимостях для данного пакета уже присутсвуют."
    f_show
    exit 0
  fi
  ${INST_PROG} -s install ${OPTARG} | grep Inst | cut -d ' ' -f 2 > ${INST_BASE}/${OPTARG}
  echo `cat ${INST_BASE}/${OPTARG}`
}

# Функция удаления данных о зависимостях.
f_remove() {
  rm ${INST_BASE}/${OPTARG}
}

# Функция вывода данных о зависимостях.
f_show() {
  echo `cat ${INST_BASE}/${OPTARG}`
}

# Функция вывода списка пакетов, для которых есть записи о зависимостях.
f_list() {
  echo `ls ${INST_BASE}`
}

# Функция вывода справки.
f_help() {
echo "Использование: depends_store.sh КЛЮЧ [ПАКЕТ]"
echo "  -i ПАКЕТ      записать данные о зависимостях для пакета"
echo "  -r ПАКЕТ      удалить данные о зависимостях для пакета"
echo "  -s ПАКЕТ      показать данные о зависимостях для пакета"
echo "  -l              вывести список пакетов, для которых записаны данные о зависимостях"
echo "  -h              показать эту справку и выйти"
}

# Проверка на наличие аргументов коммандной строки.
if [ $# -eq "0" ]
then
  f_argerror
fi

# Проверка на наличие директории для хранения данных о пакетах и создание таковой в случае отсутсвия.
if [ ! -e ${INST_BASE} ]
then
  mkdir -p ${INST_BASE}
fi

# Перебор параметров командной строки.
getopts ":i:r:s:lh" Option
case $Option in
  i)
    f_install
  ;;
  r)
    f_remove
  ;;
  s)
    f_show
  ;;
  l)
    f_list
  ;;
  h)
    f_help
  ;;
  *)
    f_argerror
  ;;
esac

exit 0


Скрипт до безобразия простой, так что всё должно быть понятно из комментариев. :) Получился такой себе небольшой костыль над apt-get.
Работать с ним просто.
Нашли нужный пакетик, сказали на него ./depends_store.sh -i и всё запомнилось в базе. Поработали с пакетом, сделали apt-get purge `./depends_store.sh -s имя_пакета` && ./depends_store.sh -r имя_пакета и забыли о нём.

четверг, 14 мая 2009 г.

Замена содержимого в файлах по шаблону

Замена во всех файлах в поддиректориях одного слова на другое.
find ./ -type f | xargs perl -pi -e 's/oneword/anotherword/g'

вторник, 28 апреля 2009 г.

Рекурсивное удаление файлов

рекурсивное удаление всех файлов в директории и её поддиректориях:
find ./ -type f -delete

Скрипт работы с cd/dvd-дисками в консоли.

Вот, роясь на просторах винта, откопал старый скрипт для записи/очистки и т.д. дисков в консоли. Писал во времена, когда не признавал почти никаких GUI-приложений.


#!/bin/bash
#
TMPFILE=/home/cppmm/wtmp/cdrom.iso

# Определение действия.

case $1 in
wr)
FUNC="f_write"
;;
cp)
FUNC="f_copy"
;;
cl)
FUNC="f_clear"
;;
ch)
FUNC="f_check"
;;
wi)
FUNC="f_write_iso"
;;
help)
FUNC="f_help"
;;
*)
FUNC="f_help"
;;
esac
shift

# Определение параметров.
until [ -z $1 ]
do
if [ "$1" = "-d" ]
then
DIR="$2"
shift
fi
if [ "$1" = "-s" ]
then
SPEED="$2"
shift
fi
if [ "$1" = "-o" ]
then
ODISK="$2"
shift
fi
if [ "$1" = "-i" ]
then
IDISK="$2"
shift
fi
if [ "$1" = "-f" ]
then
ISO="$2"
shift
fi
shift
done

# Функйия проверки наличия переменных и оповещения.
f_var_check() {
case "$1" in
v_help)
echo "Для справки: cd.sh help"
exit 0
;;
v_dir)
if [ -z "$DIR" ]
then
echo "Нужно указать директорию, подготовленную для записи."
f_var_check v_help
fi
;;
v_odisk)
if [ -z "$ODISK" ]
then
echo "Нужно указать устройство, производящее запись."
f_var_check v_help
fi
;;
v_idisk)
if [ -z "$IDISK" ]
then
echo "Нужно указать устройство, с которого производится копирование."
f_var_check v_help
fi
;;
v_speed)
if [ -z "$SPEED" ]
then
SPEED="4"
echo "Скорость записи не установленна. По-умолчанию 4"
echo "Продолжить? [Y/n]: "
read ANSWER
case $ANSWER in
[nN])
f_var_check v_help
;;
*)
;;
esac
fi
;;
v_eject)
eject -r /dev/${ODISK}
echo "Вставьте записываемый диск и нажмите Enter."
read ready
eject -t /dev/${ODISK}
;;
v_iso)
if [ -z "$ISO" ]
then
echo "Укажите файл образа."
f_var_check v_help
fi
;;
esac
}

# Функция записи дирректории на диск.
f_write() {
f_var_check v_odisk
f_var_check v_dir
f_var_check v_speed
mkisofs -V "Disk" -l -J -R -v -o ${TMPFILE} ${DIR}
f_var_check v_eject
cdrecord -v -dev=/dev/${ODISK} -speed=${SPEED} ${TMPFILE}
rm -f ${TMPFILE}
}

# Функция копирования диска.
f_copy() {
f_var_check v_odisk
f_var_check v_idisk
f_var_check v_speed
dd if=/dev/${IDISK} of=${TMPFILE} bs=2048
f_var_check v_eject
cdrecord -v -dev=/dev/${ODISK} -speed=${SPEED} ${TMPFILE}
rm -f ${TMPFILE}
}

# Функция очистки диска.
f_clear() {
f_var_check v_odisk
cdrecord dev=/dev/${ODISK} -blank=all
}

# Функция проверки размера будующего образа.
f_check() {
f_var_check v_dir
echo "Размерв байтах:"
expr `mkisofs -print-size -quiet $DIR` \* 2084

}

# Функция записи iso-образа.
f_write_iso() {
f_var_check v_odisk
f_var_check v_iso
f_var_check v_speed
cdrecord -v -dev=/dev/${ODISK} -speed=${SPEED} ${ISO}
}

# Функция помощи.
f_help() {
echo " Использование: cd.sh ДЕЙСТВИЕ ОПЦИИ"
echo " Действия:"
echo " wr запись директории на диск."
echo " cp копирование с диска на диск."
echo " cl очистка диска."
echo " ch проверка размера будущего образа диска из директории."
echo " wi запись на диск образа."
echo " Опции:"
echo " -d Директория, подготовленная для записи."
echo " -f Файл ISO."
echo " -i Исходный диск."
echo " -o Диск, подготовленный для записи."
echo " -s Скорость записи."
}

$FUNC

четверг, 12 марта 2009 г.

Смена локали. Debian.

До недавнего времени использовал везде исключительно koi8-r. Но, всё течёт, всё изменяется. Решил перейти на utf-8.
Сама смена локали порблем не вызывает - dpkg-reconfigure locales и всё. С этим просто. Но дело в том, что имена всех файлов остаются в koi8-r. Тут пришлось немного поковыряться.
Первое, за что взялся - за колекцию музыки. Есть такая замечательная утилита EasyTag. Давно пользуюсь ей(все теги у меня уже давно в UTF). Она же умеет менять имена файлов в соответствии с тегами.
А вот для всех остальных файлов пришлось наваять маленький скриптик.
Для начала, копирую все файлы, которые надо переименовать в отдельную директорию. Далее, создаю временный файл с листингом этой директории:
ls -1 tmpdir/ > tmpfile
Этот файл надо слегка обработать. ls добавляет туда неотображаемые символы, которые в скрипте обрабатывать мне показалось сложновато. Я их просто убрал с помощью vim. В командном режиме:
%s/\e\[0m//g
Теперь собственно скрипт:

#!/bin/bash
#
STRN=$2

for((i=1;i<=$STRN;i++)) do
# Получаем каждое определённое имя файла в UTF по очереди.
UTFNAME=`cat tmpfile | iconv -f koi8-r -t utf-8 | tail -n ${i} | head -n 1`
# Получаем каждое отдельное текущее имя файла
KOI8NAME=`ls -1 ${1} | tail -n ${i} | head -n 1`
rename ${1}"${KOI8NAME}" new/"$UTFNAME"
done

Число STRN - количество файлов из листинга. Это число можно получить с помощью cat -n tmpfile. Директорию new создал руками. Всё. После отработки скрипта(в качестве первого аргумента даём ему tmpdir, а второго -количество файлов), в new будут лежать все наши файлики с именами в utf-8.

P.S. Перемещать файлы, предназначенные для переименования во временную директорию надо только с помощью cp! Никаких mc.

Update: В обсуждении этого способа на welinux.ru подсказали, что есть утилита convmv. Вердикт - гуглите, перед тем, как браться за что-то! :)

Update2: Оказывается всё ещё проще. В Debian есть пакет, специально предназначенный для смены локали на utf-8: utf8-migration-tool

вторник, 20 января 2009 г.

Книги на телефоне.

Являюсь счастливым обладателем телефона Sony Ericsson k320i.
Отличная модель, к слову. Устраивает во всём.
Так как практически вся библиотека хранится в цифре, а читать хочется не только за компом, решил обзавестись читалкой на телефоне.
Ставить какие-нибудь java-книги и т.д. очень не хотелось. К тому же почти сразу появилась идея читать с помощью встроенного броузера. Но сразу же столкнулся с проблемой оперативной памяти. Броузер на телефоне не мог открывать большие файлы. Надо их как-то резать. Сперва ещё планировал каждый из маленьких текстовых файлов форматировать в html, однако оказалось, что встроенный броузер понимает txt(правда только в кодировке utf-8). В итоге решилось всё простым скриптом:

% cat textrebuild.sh
#!/bin/bash
#
# Разбиваем исходный файл на куски по 20000 байт.
split -b 20000 -d $1;
# Удаляем исходный файл
rm -f $1;
# Все кусочки переименовываем в файлы
# вида x<порядковый номер>.txt
# и перекодируем в utf-8, удаляя исходные.
FLIST=`ls ./ | grep -v textrebuild.sh`
a=0
for i in $FLIST
do
a=`echo "${a} + 1" | bc`;
cat $i | iconv -f koi8-r -t utf-8 > x${a}.txt;
rm -f $i
done

Вот и всё. Работает всё просто. Натравливаем скрипт на обычный текстовый файл с книгой и получаем на выходе кучу маленьких текстовых файлов в юникоде. Всё это потом скидывается на телефон через usb и читается по порядку в соответствии с порядковым номером.

понедельник, 11 августа 2008 г.

Подсчёт траффика в Linux с помощью pmacctd.

Система подсчёта траффика

Учётная система работает на основе утилиты pmacctd. Утилита записывает весь, проходящий через интерфес траффик и скидывает это всё в лог-файл. После этого скрипты сортируют получившийся дамп по адресам клиентов, разделяет по дням недели и месяцам, а так же создаёт бекап дампа. Адреса клиентов система берёт из основного конфига прокси-сервера.

Скрипт запуска, останова и считывания адресов клиентов учётки

Находится в /etc/ini.d/ Отрабатывает с параметром start при старте системы и параметром stop, при останове. После добавления нового пользователя, надо делать /etc/ini.d/pmacct restart

#!/bin/sh
#

## Глобальные переменные
### Пути к утилитам, по которым скрипт может обращаться. Не обязательная переменная, но для подстраховки не помешает.
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
### Расположение собственно исполняемого файла утилиты pmacctd
DAEMON=/usr/sbin/pmacctd
### Имя работающего демона
NAME=pmacctd
### Описание.
DESC="traffic accounting system"
### Директория для хранения настроек учётной системы.
CONFDIR=/etc/pmacct
### Директория для хранения логов.
LOGDIR=/var/log/pmacctd
### Инклудим конфиг.
. $CONFDIR/pmacctd.conf

### Проверяем наличие исполняемого файла демона. Если отсутствует, завершаем работу.
test -x $DAEMON || exit 0

### Функция останова.
stop () {
 killall -INT $NAME
}

### Функция старта.
start () {
#### Вытягиваем из конфига прокси-сервера имена и ip-адреса пользователей и сохраняем из в файл stat.conf в директории конфигов.
     grep 255.255.255.255 /etc/squid/squid.conf | grep -v 127.0.0.1 | grep -v '#' | awk '{print $2, $4}' | cut -f 1 -d / > $CONFDIR/stat.conf
#### Собственно запускаем демона в фоновом режиме и складываем всю статистику по траффику в файл pmacctd.log в лог-директории.
     $DAEMON -c $PRIMITIVE -i $INTERFACE -r $INTERVAL -P print >> $LOGDIR/pmacctd.log &
}

### Меню выбора используемой функции из первого аргумента после скрипта.
case "$1" in
start)
     echo -n "Starting $DESC: "
     start
     echo "$NAME."
     ;;
stop)
     echo -n "Stopping $DESC: "
     stop
     echo "$NAME."
     ;;
restart)
     echo -n "Restarting $DESC: "
     stop
     sleep 1
     start
     echo "$NAME."
     ;;
*)
     N=/etc/init.d/$NAME
     echo "Usage: $N {start|stop|restart}" >&2
     exit 1
     ;;
esac

exit 0




Конфиг.


Значения берутся из man pmacctd.

PRIMITIVE=src_host,dst_host
INTERFACE=eth0
INTERVAL=1


Скрипт скидывания ежедневной статистики

Запуск скрипта прописан в файле /etc/crontab:
01 4 * * * root /usr/sbin/pmacctdaily
Он отрабатывает автоматически каждый день в 04:01:00 по времени сервера.

#!/bin/bash
#
## Конфигурационная директория
CONFDIR=/etc/pmacct
## Лог-директория
LOGDIR=/var/log/pmacctd
## Текущая дата в формате ддммгггг
DATE=`date +%d%m%Y`
## Вычисление пользовательских ip-адреса.
USERSIP=`cat $CONFDIR/stat.conf | awk '{print $2}'`
## Останов учётной системы для того, чтобы она не обращалась к логам во время работы с ними данного скрипта.
/etc/init.d/pmacct stop >/dev/null
## Создание директории для траффика за сутки до текущей даты
mkdir $LOGDIR/$DATE 2>/dev/null
## Пока в памяти лежат пользовательские ip-адреса, обработать каждый из них по-очереди.
for i in $USERSIP
do
#### Вычисляем количество бит в каждой следующей записи из лога, в которой упоминается текущий ip-адрес
BYTES=`grep -w $i $LOGDIR/pmacctd.log | awk '{print $16}'`
ALLBYTES=0
##### Прибавляем каждое новое вычисленное количество битов к переменной ALLBYTES
for b in $BYTES
do
ALLBYTES=$((ALLBYTES+b))
done
##### Вычисляем имя пользователя с текущим ip-адресом
USERNAME=`grep -w $i $CONFDIR/stat.conf | awk '{print $1}'`
#### Скидываем в файл с именем текущего пользователя значение переменной ALLBYTES
echo $ALLBYTES > $LOGDIR/$DATE/$USERNAME
done
##### Архивируем общий лог и сохраняем его в директорию с файлами статистики пользователей за сутки.
gzip $LOGDIR/pmacctd.log
mv $LOGDIR/pmacctd.log.gz $LOGDIR/$DATE/
Запускаем учётную систему.
/etc/init.d/pmacct start >/dev/null
В общей сложности при нынешней нагрузке скрипт отрабоатывает примерно за 10-15 секунд. Чем больше будет пользователей и траффика, тем больше понадобится времени, но для того, чтобы дойти хотя бы до минуты выполнения, надо увеличить объёмы в несколько раз.


Скрипт скидывания ежемесячной статистики

Запуск скрипта прописан в файле /etc/crontab:
01 5 1 * * root /usr/sbin/pmacctdmonthly
Он отрабатывает автоматически каждый первый день месяца в 05:01:00 по времени сервера.
#!/bin/bash
#
### Конфигурационная директория
CONFDIR=/etc/pmacct
### Лог-директория
LOGDIR=/var/log/pmacctd
### Текущий месяц в формате мм
MONTH=`date +%-m`
### Текущий год в формате гггг
YEAR=`date +%Y`
Временная директория
TMPDIR=/tmp/pmacctd
## Так как скрипт выполняется первого числа, а нам надо сделать статистику за предыдущий месяц, делаем проверку, не первое ли сегодня января и присваиваем переменным месяца и года нужные нам значения.
#### Отдельное примечание. Из-за того, что в bash по умолчанию числа, начинающиеся с 0, автоматически считаются числами восьмеричой системы счисления,
#### приходится делать более сложную проверку, сравнивая значения месяцев, как строки, и только потом присваивать им какие-либо значения.
if [[ $MONTH == 01 ]]
then
LASTMONTH=12
LASTYEAR=$((YEAR-1))
else
if [[ $MONTH == 11 || $MONTH == 12 ]]
then
LASTMONTH=$((MONTH-1))
LASTYEAR=$YEAR
else
LASTMONTH=$((MONTH-1))
LASTMONTH=0$LASTMONTH
LASTYEAR=$YEAR
fi
fi
## Создаём директорию вида ммгггг для хранения статистики за месяц.
mkdir $LOGDIR/$LASTMONTH$LASTYEAR
## Считываем все директории с файлам посуточной статистики за прошедший месяц.
DIR=`ls $LOGDIR | grep $LASTMONTH$LASTYEAR`
for i in $DIR
do
#### Поочереди, в каждой из этих директорий находим файлы по именам пользователей
USERNAME=`ls $LOGDIR/$i/`
for n in $USERNAME
do
###### Во временной директории создаём файл с несуммированной статистикой на каждого пользователя.
BYTES=`cat $LOGDIR/$i/$n`
echo $BYTES >> $TMPDIR/$n
done
done
#### Суммируем статистику из временной директории на каждого пользователся,
#### Складываем её в вышесозданную директорию и
#### удаляем временные файлы.
for i in $DIR
do
USERNAME=`ls $LOGDIR/$i/ | grep -v gz`
for nn in $USERNAME
do
ALLBYTES=0
BYTES=`cat $TMPDIR/$nn`
for b in $BYTES
do
ALLBYTES=$((ALLBYTES+b))
echo $ALLBYTES > $LOGDIR/$LASTMONTH$LASTYEAR/$nn
done
done
done
rm -rf $TMPDIR
В итоге в Лог-директории мы получаем каталог с номером прошедшего месяца и года вида ммгггг, в котором лежат файлы, имя каждого из которых - это имя пользователя, а содержимое - траффик за прошедший месяц.