Мини заметки — выпуск 6
20 апреля 2012
Главные темы шестого выпуска: комбинаторика на Haskell, исправление кодировки без использования iconv, полуавтоматическая поисковая оптимизация заголовков, настройка unbound и pptp, а также создание мгновенного снимка файловой системы под FreeBSD. Предыдущие выпуски: первый, второй, третий, четвертый и пятый.
1. Размещение «шариков» по «коробкам» на Haskell
Дано N разноцветных шариков, M коробок различной вместимости, а также стол бесконечной вместимости. Нужно получить список всех возможных размещений (не путать с размещением в комбинаторике) шариков по коробкам и столу. Вместо шариков могут быть яблоки или посылки, а вместо коробок — корзины или грузовики, суть от этого не меняется. Решение на Haskell:
import Data.List
-- первый аргумент - список "шариков"
-- второй аргумент - вместимость "коробок"
placements :: Eq a => [a] -> [Int] -> [[[a]]]
placements itemsList [] = [[ itemsList ]]
placements itemsList (maxItems:maxItemsTail) =
[ (s:t) | s <- seqList, t <- allTails s]
where
-- все варианты размещения "шариков" в текущей "коробке"
seqList = filter (\s -> length s <= maxItems)
$ subsequences itemsList
-- все варианты размещения "шариков"
-- в остальных "коробках" и на "столе"
allTails s = placements (itemsList \\ s) maxItemsTail
Если вам попадалось готовое решение, поделитесь, пожалуйста, ссылкой.
2. Настройка unbound
Поднятие локального DNS сервера может быть целесообразным по крайней мере в двух случаях. Первый — когда вам хочется ускорить загрузку веб-страниц за счет кэширования ответов DNS сервера провайдера. Если у провайдера тормозной DNS, прирост скорости весьма ощутим. Второй случай — когда часть доменных имен вы хотите резолвить на одних DNS серверах, а часть — на других, например, если вы работаете дома через VPN.
Для этих целей идеально подходит DNS сервер unbound:
После установки пишем в /usr/local/etc/unbound/unbound.conf что-то вроде:
# принимаем пакеты только с локалхоста
interface: 127.0.0.1
access-control: 127.0.0.0/8 allow
# минимальный и максимальный TTL
cache-min-ttl: 21600
cache-max-ttl: 86400
forward-zone:
# за адресами доменов компании ходим по VPN
name: "company.example.ru."
forward-addr: 33.33.33.1
forward-addr: 33.33.33.2
forward-zone:
# остальные домены резолвим у провайдера
name: "."
forward-addr: 192.168.0.1
В /etc/rc.conf прописываем:
Запускаем:
Проверяем:
dig @127.0.0.1 intra.company.example.ru
В /etc/resolv.conf прописываем:
Чтобы resolv.conf не перезаписывался благодаря DHCP провайдера, в /etc/dhclient.conf пишем:
supersede domain-name-servers 127.0.0.1;
}
Некоторые приложения понадобится перезапустить, иначе они не увидят новых настроек.
3. Использование разных ssh-ключей для разных серверов
Что делать, если требуется получить доступ к N серверам с одной машины, используя различные identity file для каждого сервера?
Копируем закрытый ключ для i-го сервера, например, в ~/.ssh/id_rsa.i-server (также копируем открытый ключ в id_rsa.pub.i-server — чтобы не потерять), меняем права доступа на 600, а затем пишем в ~/.ssh/config:
IdentityFile ~/.ssh/id_rsa.i-server
User myusername
Повторяем описанные действия для i от 1 до N.
4. Настройка pptp под FreeBSD
Устанавливаем pptpclient:
Правим /etc/ppp/ppp.conf:
set authname mylogin
set authkey mypassword
set timeout 0
set ifaddr 0 0
# весь трафик - через VPN!
# add default HISADDR
# через VPN ходим только в заданную подсеть
set 123.45.67.0/24 HISADDR
# ... и к заданному хосту
set 45.67.89.10 HISADDR
Указываем, через какой шлюз гнать трафик к VPN серверу:
Проверяем:
Варнинги типа «/bin/ip: not found» игнорируем, логи смотрим в /var/log/ppp.log. По умолчанию в ppp.conf прописано «enable dns», что приводит к перезаписи resolv.conf. Если вы оставили эту опцию, то после разрыва соединения с VPN сервером должны вручную восстановить resolv.conf:
Также после разрыва соединения понадобится восстановить шлюз по умолчанию:
Напоминаю, что посмотреть все роуты можно командой «netstat -nr».
5. Создание мгновенного снимка ФС во FreeBSD
Снапшоты файловой системы во FreeBSD можно создать несколькими способами. Наиболее простым, по моим представлениям, является следующий:
$ echo "1111" > test.txt
# snapshot make -g4 /usr:backup
Здесь флаг -g задает максимальное количество снапшотов. Если превысить это число, происходит автоматическая ротация.
Filesystem User User% Snap Snap% Snapshot
/usr 146GB 25.8% 346MB 0.1% backup.0
# mkdir /mnt/backup
# snapshot mount /usr:backup.0 /mnt/backup
# cat /mnt/backup/home/eax/test.txt
1111
$ echo "2222" > test.txt
# cat /mnt/backup/home/eax/test.txt
1111
# snapshot umount /mnt/backup
# ls -la /usr/.snap/
total 357652
drwxrwxr-x 2 root operator 512 4 май 11:40 .
drwxr-xr-x 17 root wheel 512 14 окт 21:59 ..
-r-------- 1 root operator 627341157960 4 май 12:12 backup.0
# snapshot make -g0 /usr:backup
Мгновенные снимки часто используются при резервном копировании. Например, если на сервере крутится некая СУБД, мы можем останавливаем ее (или временно запретить запись и скинуть все данные на диск), создать снапшот файловой системы, после чего снова запускаем СУБД (разрешить запись) и сделать резервную копию из снапшота.
В результате сервер не простаивает, а мы получаем резервную копию данных в непротиворечивом состоянии. За счет использования механизма copy-on-write создание мгновенного снимка происходит очень быстро (на то он и мгновенный), а место на диске расходуется с умом.
6. Полуавтоматическая поисковая оптимизации заголовков
Дан список URL и поисковых запросов, по которым продвигаются соответствующие страницы. Следующий скрипт проверяет, заголовки каких страниц следует оптимизировать:
# check-header.pl v 0.1
# (c) Alexandr A Alexeev 2012 | http://eax.me/
use strict;
use warnings;
use utf8;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new();
while(my $line = <>) {
chomp($line);
my ($url, $query) = split /\t/, $line;
utf8::decode($query);
my $title;
eval {
$title = $ua->get($url)
->res->dom->html->head->title->text;
};
if($@) {
print "ERROR:\t$url\n";
next;
}
if(titleMatch($title, $query)) {
print "OK:\t$url\n";
} else {
utf8::encode($query);
print "FIXME:\t$url\t$query\n";
}
}
sub titleMatch {
my($title, $query) = @_;
$title = lc $title;
$query = lc $query;
my @tmp = split /\s+/, $query;
for my $q(@tmp) {
return 0 if(index($title, $q) < 0);
}
return 1;
}
Проверка довольно топорная — если страница продвигается по запросу «купить яблоки», то в title должны содержаться слова «купить» и «яблоки». Этот скрипт удобно использовать со скриптом из десятого пункта предыдущего выпуска мини-заметок.
7. Как скопировать музыку с CD под UNIX
В портах FreeBSD есть такая замечательная утилита audio/ripit, предназначенная для конвертирования музыки с CD дисков в MP3. Устанавливаем, немного правим /usr/local/bin/ripit.pl:
my $outputdir = "/home/user/cdrip";
Затем просто вставляем диск в CD привод и говорим из под рута «ripit». Музыка в формате MP3 магическим образом окажется в директории $outputdir.
8. Удобные сочетания клавиш в bash
Недавно коллега показал мне два очень удобных сочетания клавиш в bash. До этого я умел пользоваться только стрелочками Вверх и Вниз, а также клавишей Tab.
Сочетание Ctr+R позволяет быстро выполнять команды, набранные ранее. Жмем Ctr+R и вводим часть команды. Если bash предложил то, что мы хотели, жмем Enter. Если снова нажать Ctr+R, будет предложена другая команда. Нажатие Escape возвращает нас в нормальный режим.
Сочетание Alt+точка подставляет в вводимую команду последний использованный аргумент. Например, если выполнить команду «ls -la», затем набрать «cat » и нажать Alt+точка, команда превратиться в «cat -la». Повторное нажатие Alt+точка подставляет другие аргументы, используемые ранее. Это сочетание особенно удобно при выполнении нескольких команд над файлами, к которым мы обращаемся по абсолютным или длинным относительным путям.
Может, есть еще какие-то сочетания клавиш, которые мне давно следовало бы держать на вооружении?
9. Утилита sloth
Если какой-то фоновый процесс съедает много ресурсов, а (re)nice не помогает, попробуйте утилиту sloth:
Эта программа бомбит процесс сигналами SIGSTOP и SIGCONT, что существенно замедляет его выполнение:
MD5 (PCBSD9.0-x86-DVD.iso) = 805eebb4d24e2ada0466d5baa1997b45
real 1m46.598s
user 0m17.914s
sys 0m7.744s
$ time sloth 5000 md5 PCBSD9.0-x86-DVD.iso
MD5 (PCBSD9.0-x86-DVD.iso) = 805eebb4d24e2ada0466d5baa1997b45
real 7m16.996s
user 0m18.523s
sys 0m7.713s
Если для вашей системы не оказалось готового пакета, вы можете собрать sloth из исходников. Последние представляют собой сотню строк на языке Си.
10. Исправление кодировки без использования iconv
Недавно мне попался дамп базы данных с испорченной кодировкой. Декодер студии Артемия Лебедева определил, что исправить кодировку можно путем перекодирования текста из cp1252 в cp1251. Но ни enconv, ни iconv никак не могли справиться этой, казалось бы, элементарнейшей задачей. В итоге пришлось написать такой скрипт:
# decoder.pl v 0.2
# (c) Alexandr A Alexeev 2012 | http://eax.me/
use strict;
use warnings;
use utf8;
use List::MoreUtils qw/uniq/;
# http://www.artlebedev.ru/tools/decoder/advanced/
my @bad = split //,
'??????????????????????????????????????????????????????????????????';
my @good = split //,
'абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ';
my %map;
$map{$_} = shift @good for (@bad);
while(my $line = <>) {
utf8::decode($line);
$line = join '', (
map { defined $map{$_} ? $map {$_} : $_ } (split //, $line)
);
utf8::encode($line);
print $line;
}
Как обычно, я буду несказанно рад вашим вопросам и дополнениям. Также мне было бы интересно узнать, какие пункты этого выпуска мини-заметок больше всего вам понравились и почему.
Дополнение: Мини заметки — выпуск 7
Метки: Всячина.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.