четверг, 6 августа 2015 г.

Захват и обработка видео из консоли

Для обработки видео существует такая утилита, как ffmpeg, которая поддерживает огромное количество кодеков и форматов аудио и видео.

Захват видео с экрана

$ ffmpeg -y -f x11grab -threads 0 -r 10 -s 1920x1080 \
-i :0.0 -preset slower -tune stillimage -an file.mkv
Описание:
  • -y – перезаписывать существующие файлы;
  • -f x11grab – запись с экрана;
  • -threads 0 – автоматически задавать максимальное количество потоков, если указать, число, то можно задать максимальное количество потоков;
  • -r 10 – кадров в секунду;
  • -s 1920x1080 – размер изображения;
  • -i :0.0 – экран для захвата (можно и удалённо), если указать :0.0+10,20 , то запись будет идти с соответствующим смещением на экране;
  • -preset slower — предустановка режима записи, существует множество (от ultrafast – самый быстрый режим с большим битрейтом, до placebo – очень медленный режим с минимальным битрейтом), лучше смотреть man x264 и подобрать настройку под производительность системы и выбранную частоту кадров;
  • -tune stillimage – предустановка для типа изображения, в данном случае - статическое изображение, т.е. запись с экрана обычных действий (игры записать не получится, для этого нужно указать film или вообще не указывать ничего);
  • -an – записывать без звука.
Кодек для записи видео можно указать явно через -vcodec …, по умолчанию для mkv используется libx264.
Для записи звука нужно указать -f oss -i /dev/dsp -acodec libfaac -ab 192k для oss (для ALSA не знаю…).
  • -f oss – запись через oss;
  • -i /dev/dsp – устройство записи (если несколько звуковых карт, указать своё);
  • -acodec libfaac – кодек записи, этот более-менее оптимальный, хотя faac гораздо хуже оригинального от nero;
  • -ab 192k — битрейт аудио.

Разрезать видео

ffmpeg -i video.mkv -ss 10:20 -t 15:00 -vcodec copy -acodec copy video2.mkv
Здесь следует сказать только о двух параметрах:
  • -ss – смещение относительно начала файла мин:сек;
  • -t – длина видео. 
Время может быть указано в формате  hh:mm:ss[.xxx] вплоть до миллисекунд.

Склеить несколько видео

Судя по всему, можно склеивать только видео формата ts и mpg. Для склеивания видео в формате mkv или mp4 с кодеком h264 видимо можно только перекодировав.
ffmpeg -i concat:"video1.mpg|video2.mpg" -vcodec copy -acodec copy video_out.mpg
Три варианта использования с перекодированием:
  • Первый вариант с последовательным перекодированием каждого видео:
    ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
    ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
    cat intermediate1.mpg intermediate2.mpg > intermediate_all.mpg
    ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
    
  • Вариант с отдельным перекодированием и одновременной склейкой и обратным перекодированием средствами ffmpeg:
    ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
    ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
    ffmpeg -i concat:"intermediate1.mpg|intermediate2.mpg" -c copy intermediate_all.mpg
    ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
    
  • Вариант, позволяющий делать всё параллельно (идеально подходит для многоядерных процессоров):
    mkfifo intermediate1.mpg
    mkfifo intermediate2.mpg
    ffmpeg -i input1.avi -qscale:v 1 -y intermediate1.mpg < /dev/null &
    ffmpeg -i input2.avi -qscale:v 1 -y intermediate2.mpg < /dev/null &
    cat intermediate1.mpg intermediate2.mpg |\
    ffmpeg -f mpeg -i - -c:v mpeg4 -acodec libmp3lame output.avi
    

четверг, 30 июля 2015 г.

Как перенаправить все запросы в Apache2 одному скрипту

В web-программировании существует проблема, что при запросе разных страниц (речь идёт о php) вызываются разные скрипты, то есть программа на php имеет множество точек входа, что не есть правильно, т.к. в рамках одного приложения должны производиться какие-то одинаковые действия при запуске и остановке (открытие файлов, инициализация объектов, подключение к базе данных и т.д.), поэтому в каждом файле необходимо включать единый скрипт инициализации, что не совсем удобно.
При другом подходе, когда существует один скрипт, но запрос страниц происходит через get-параметры, требуется чётко следить за путями к содержанию страниц, т.е. если мы хотим включить в страницу некоторый файл html, который расположен не в корневом каталоге, и который имеет картинки и другой контент, то нужно позаботится о том, чтобы ссылки на странице были относительно файла скрипта корректными. Такой подход также используется в сайтах, написанных, например, на Perl или Python.
Чтобы избежать такой ситуации, но так, чтобы пользователь видел адрес запрашиваемой страницы в нормальном виде, можно включить обработчик, то есть при запросе страницы будет передано управление одному скрипту, который получит в параметрах адрес запрашиваемой страницы. Таким образом, например, можно написать контент для сайта в виде простых html-файлов, а оформление страницы будет задаваться единым шаблоном с помощью одного скрипта.
Существует по крайней мере 2 способа передачи управления одному скрипту. Заранее скажу, что после включения/выключения модов следует перезапускать Apache.

Мод Actions

Для того, чтобы задействовать эту возможность, нужно включить мод:
# a2enmod actions
Далее в настройках виртуального хоста или в файле .htaccess в корневой папке сайта нужно добавить следующее:
# Документы этого типа мы желаем "пропускать" через обработчик
AddHandler handler .html .htm .php
# Замкнем имя обработчика на конкретный файл
Action handler /index.php?
Здесь handler – просто удобное название обработчика.
/index.php? указывает на то, что всё будет перенаправлено скрипту /index.php через GET-параметры. Если не указать знак вопроса, то параметры будут переданы через POST.
Скрипту будет передан один параметр – строка запроса, т.е., например, если мы введём http://example.com/somedir/file.html?action=foo, то скрипт получит параметр /somedir/file.html?action=foo.
Здесь есть минус – параметры, переданные пользователем, нужно обрабатывать самостоятельно, то есть в php они будут недоступны в массиве $_GET. Кроме того, файлы .php почему-то не хотят перенаправляться, хотя им можно дать расширение html, и тогда пользователю будет казаться, что сайт – статический.

Мод Rewrite

Можно активизировать мод rewrite, который просто подменяет введённый адрес на заданный. Для включения мода нужно ввести:
# a2enmod rewrite
После чего в .htaccess или в конфиг сайта добавить:
#Включить подмену адреса
RewriteEngine on
#Подменять, только, если это не index.php
RewriteCond %{REQUEST_URI}  '!=/index.php'
#Поменять все php, html и htm страницы
RewriteRule ^.*\.(php|html|htm)\??.*$ /index.php
  • RewriteEngine on – обязательно вводится, чтобы подмена работала.
  • RewriteCond – необязательный параметр, используется условие подмены, в данном
случае проверяется, чтобы сам скрипт не был перенаправлен сам себе (хотя может ничего страшного и не будет, я не пробовал отключать).
  • RewriteRule – самый главный параметр, указывает, как подменять запрос, здесь
используются регулярные выражения, первое – что подменять, второе – чем.
По сравнению с обработчиком, параметры GET передаются в php в массив $_GET, в Perl доступны через модуль CGI и т.д. Строка запроса доступна через $SERVER["REQUEST_URI"], из которой можно вытянуть запрашиваемый файл и обработать его должным образом.
Лично я пользуюсь именно таким способом.

суббота, 25 июля 2015 г.

Настройка виртуальных хостов в Apache2 (в linux)

Основные настройки сервера можно найти в /etc/apache2 (debian):
  • apache2.conf – общие настройки, их можно и не трогать;
  • sites-available/*.conf – доступные настройки для сайтов;
  • sites-enabled/*.conf – настройки активных сайтов;

Виртуальные хосты

Чтобы добавить сайт, нужно настроить виртуальный хост для него (нужен домен). То есть по запросу сайта по адресу example.com будут задействованы одни настройки, а если на этом же сервере, но запрос сайта будет по адресу test.com, то будут задействованы другие настройки. Таким образом, разегистрировав несколько доменов или используя несколько поддоменов, можно разместить на одном сервере несколько сайтов, независимых друг от друга.
Для включения нужно создать файл в sites-available/ с расширением (обязательно) .conf, можно скопировать файл по умолчанию, находящийся в той же папке, чтобы не писать с нуля.
Примерное содержание файла:
<VirtualHost *:80>
 ServerName example.ru
 ServerAlias www.example.ru

 ServerAdmin admin@example.ru
 DocumentRoot /var/www/example.ru/
 
 <Directory /var/www/example.ru>
  AllowOverride All
  Order allow,deny
  allow from all
 </Directory>

 ErrorLog ${APACHE_LOG_DIR}/error.log
 CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

  • *:80 указывает, что с любых адресов будут обрабатываться запросы на порт 80.
  • ServerName – адрес виртуального хоста, т.е. все запросы на сервер по доменному  имени example.ru будут обрабатываться именно с этими настройками.
  • ServerAlias – просто дополнительное имя.
  • ServerAdmin – почта администратора сервера (не знаю зачем, и как действует).
  • DocumentRoot – расположение данных сайта.
  • Directory… – настройки каталога, каталог может быть любым, в том числе и вложенным в основной, и даже корень /.
    • AllowOverride All – позволить перезаписывать настройки для каталога из файлов .htaccess. Остальные настройки не знаю, оставил, как было по умолчанию.
  • ErrorLog и CustomLog – логи сервера, также есть настройки для уровня ведения логов.

Включение виртуального хоста

Чтобы включить хост, нужно запустить команду a2ensite <фал настроек (без пути)> от суперпользователя, apache сделает необходимые действия и сайт будет доступен.
Теперьм можно наполнять папку /var/www/example.ru/
После изменения конфигов нужно запускать # service apache2 reload, а после включения/выключения сайтов # service apache2 restart.

понедельник, 1 декабря 2014 г.

Проблема запуска Minecraft на Linux с установленным OSS

После обновления Minecraft до версии 1.6 появилась проблема при запуске игры с установленным OSS по умолчанию. Как выяснилось, проблема была в библиотеке OpenAL, которая поставлялась вместе с этой версией игры. Простая замена ни к чему не привела, т.к. при запуске лаунчера все файлы игры распаковывались откуда-то из архива и заменялись. Поэтому я написал свой скрипт для запуска, который вы можете посмотреть здесь. Для этого скрипта следует создать директорию, в которой будут рабочие библиотеки (libopenal.so или libopenal64.so) можно взять в системной директории вашего дистрибутива или создать символические ссылки к ним.
Данный подход имеет один большой минус -- подобный запуск не позволяет играть на серверах с проверкой лицензии. Собственно, этот способ запуска является "пиратским". Поэтому пришла в голову идея заменять файлы библиотек прямо во время запуска, но после того, как они созданы лаунчером. Подобная идея описывается здесь, но я поступил гораздо проще, я взял из указанного скрипта лишь одну строчку и получил следующий скрипт:
#/bin/bash
MC_BASE_PATH=~/.minecraft
OPENAL=/usr/lib/i386-linux-gnu/libopenal.so.1
OPENAL64=/usr/lib/x86_64-linux-gnu/libopenal.so
CURRENT=$(inotifywait -q -r -e CREATE $MC_BASE_PATH/versions/)
DIR=$(echo $CURRENT | cut -d ' ' -f 3)
DIR=$(echo $CURRENT | cut -d ' ' -f 1)$DIR
echo "Created dir: $DIR"
if [ -e "$DIR/libopenal64.so" ]
then
    ln -sf $OPENAL64 "$DIR/libopenal64.so"
    echo "OpenAL was replaced"
    exit
fi
echo "OpenAL not foud"
Суть в том, что лаунчер при запуске создаёт временную папку в versions с нативными библиотеками, а при завершении работы игры удаляет её. Сразу же после создания папки скрипт заменяет в ней файлы на символические ссылки на системные библиотеки. Я оставил только замену 64-битной версии библиотеки, если система 32-битная, то следует заменять libopenal.so. Также я указал прямой путь к системным библиотекам -- переменные OPENAL и OPENAL64, для других дистрибутивов пути могут быть другие.
Я убрал проверку создания файлов, т.к. у меня команда inotifywait срабатывала только при создании папки, это работает на Debian wheezy, на остальных системах возможно она будет срабатывать и при создании файлов, поэтому я сделал проверку на наличие файла. То, что выводит команда inotifywait можно посмотреть, введя следующую команду, находясь в папке ~/.minecraft:
while true; do inotifywait -r -q -e create versions; done
После чего запускаем лаунчер, запускаем игру и выходим из неё. Затем останавливаем этот бесконечный скрипт, нажав Ctrl-C.

среда, 29 октября 2014 г.

Пакетная запись на dvd/cd-rw в linux

Существует два способа дозаписи на dvd-r и cd-r - это мультисессия и пакетная
запись. В первом случае можно использовать утилиту growisofs:
$growisofs -Z /dev/dvd -JRV "Диск 1" file1 file2 ...
здесь -J - использовать расширение jolie для отображение юникода и длинных имён
файлов, -R - RockRidge для сохранения атрибутов posix, -V - метка тома,
последние параметры - список файлов и папок.
Диск запишется, в дальнейшем для дозаписи нужно следующее:
$growisofs -M /dev/dvd -JRV "Диск 1" file3 "file 4" ...
т.е. меняется один параметр - -Z на -M, в первом случае диск инициализируется и
записывается первая сессия, во втором - записываются последующие сессии.
Подробнее можно узнать в man growisofs.
Данная утилита может иметь другие названия в разных дистрибутивах, в Debian -
growisofs.
Перейдём ко второму случаю, он заключается в том, чтобы отформатировать диск в
файловую систему udf, а потом использовать его как флешку, т.е. записывать файлы
сразу напрямую по отдельности, также можно удалять файлы. Для этого подходит
любая болванка, даже не перезаписываемая, типа dvd-r, но в этом случае при
удалении файлов место на диске освобождаться не будет. Для работы требуется
пакет udftools, который есть в репозитории Debian, он достаточно популярен,
поэтому должен быть и в других дистрибутивов. И так, необходимы следующие
действия:

1. Подготавливаем диск.

Для dvd-rw и bd-re:
$dvd+rw-format -force /dev/dvd
Для cd-rw:
$cdrwtools -q -d /dev/cdrw
Для dvd-r и cd-r пропускаем этот шаг.

2. Форматируем в файловую систему udf

$mkudffs -r 0x0150 --media-type=dvdrw /dev/dvd
Для cd-rw media-type будет cdrw, для dvd-r - dvd и т.д.
-r означает версию udf, если не требуется ничего особого, то лучше поставить
версию поменьше (1.5 хватит для любых целей) для гарантии, что диск будет
читаться на всех ОС. Можно без этой опции, тогда версия будет 2.01.
В файле README из документации пакета udftool написано, что нужно использовать
утилиту pktsetup и использовать вместо /dev/dvd (или /dev/sr0) что-то вроде
/dev/pktcdvd/0, но у меня из-за этого были жуткие тормоза, диск записывался
полностью аж за 10 часов. Этот способ можно использовать, если не получилось
напрямую через /dev/dvd:
$pktsetup 0 /dev/dvd
$mkudffs /dev/pktcdvd/0
В дальнейшем работаем уже с этим устройством.

3. Монтируем файловую систему и работем с ней

$mount -t udf -o rw,noatime /dev/dvd /media/dvd0
noatime нужно, чтобы при чтении не обновлялось время доступа к файлам. Это
сохранит ресурс rw диска и ускорит работу за счёт уменьшения количества
операций.

4. Завершаем работу

После завершения работы сбрасываем кэш файловой системы, отмонтируем её и
вытаскиваем диск:
$sync
$umount /media/dvd0
$eject
Хотя всё выполнится автоматически, если нажать кнопку на dvd-приводе, правда
придётся подождать, т.к. операции могут занять достаточно длительное время.

Дополнительно

Если в вашей системе не разрешены вышеприведённые команды на выполнение
обычному пользователю, то следует их запускать от имени суперпользователя (кроме
команды sync).
Данный способ записи плохо подходит, если требуется забить диск до отказа
мелкими файлами, т.е. производительность очень сильно страдает от этого, и
вместо 15 минут записи образа на dvd-rw, операция может занять несколько часов.
Даже при записи одного большого файла скорость записи dvd-rw 4x снижается до 3x.
Поэтому данный способ подходит, когда требуется регулярно дописывать на диск
небольшой объём данных, например при инкрементальном резервном копировании.
А вообще, если не требуется, чтобы диск читался на windows и других системах,
можно использовать любой тип файловой системы, например ext2 (желательно, чтоб
ФС не была журналируемой). Разумеется, в этом случае подойдёт только
перезаписываемый диск. Просто вместо mkudffs используем
$mkfs.ext2 /dev/dvd
Правда ждать придётся ооочень долго… Поэтому лучше сделать так:
Создаём образ (я обычно использую разряжённый файл):
$dd if=/dev/null bs=4700MB seek=1 of=dvd.img
Форматируем его:
$mkfs.ext2 dvd.img
Записываем:
$growisofs -Z /dev/dvd=dvd.img
Монтируем диск:
$mount /dev/dvd /media/dvd0
Ну и работаем, по производительности ничего не могу сказать, т.к. делал это
только в качестве эксперимента.
Также у меня не было возможности проверить работу на dvd-ram и bluray, но
отличия, скорее всего в способе очистки и опции media-type при форматировании.

суббота, 11 октября 2014 г.

Инкрементальный бэкап в линукс

Зачастую требуется резервное копирование большого количество данных, в которых
изменяется лишь незначительная их доля. Для этой цели подходит инкрементальный
бэкап, т.е. делается один полный бэкап, а потом записываются лишь изменения в
резервируемых данных.
Я не буду здесь рассматривать все существующие способы инкрементального
резервного копирования, приведу лишь 3, которыми я пользовался.

rdiff-backup

Самое просто решение, просто указываем две папки - откуда копировать и куда
копировать. Данная утилита определяет изменения в файловой системе и записывает
лишь их. В дальнейшем можно восстановить не только последнюю копию, но и все
копии, которые были сделаны до этого. Также при помощи rdiff-backup-fs можно
смонтировать каталог с резервной копией через fuse и получить виртаульную
файловую систему с папками, соответствующими времени копирования, в которых
будут находится файлы, скопированные в это время.
На данный момент утилита имеется в репозиториях большинства популярных
дистрибутивов, поэтому установка не должна составить трудности.

Примеры

Простое резервное копирование папки /home:
$ rdiff-backup /home/ /backup/
Резервное копирование определённых папок:
$ rdiff-backup --globbing-file-list lits.txt /home/user/ /backup/
Пример содержания файла list.txt:
+ /home/user/.asoundrc
+ /home/user/.bashrc
- /home/user/bin/netbeans-7.3.1
- /home/user/bin/eclipse
- /home/user/bin/eclipse-cpp
+ /home/user/bin
+ /home/user/Books
+ /home/user/.config
+ /home/user/databases
+ /home/user/.gconf
+ /home/user/.gconfd
+ /home/user/.local/share/gtg
+ /home/user/.local/share/gnote
+ /home/user/.local/share/Psi+
+ /home/user/.profile
+ /home/user/Projects
+ /home/user/.psi
+ /home/user/.purple
+ /home/user/list.txt
+ /home/user/scripts
+ /home/user/.Skype
+ /home/user/.ssh
+ /home/user/.vim
+ /home/user/.vimrc
+ /home/user/vimwiki
+ /home/user/Документы
+ /home/user/Рабочий стол
- **
+ означает добавить файл или директорию, - - убрать из списка резервного
копирования. В данном примере добавляем определённые каталоги, при этом из папки
bin исключаем некоторые папки, которые резервировать не нужно.
Вместо файла со списком можно использовать ключи --include, --include-regexp
и прочие, подробнее в man rdiff-backup.

Особенности

Можно выделить плюсы и минусы данного метода.
Плюсы:
  • можно получить доступ к любой версии резервируемых файлов;
  • можно удалять старые бэкапы.
Минусы:
  • резервная копия хранится в виде множества файлов, которые с каждым бэкапом
    обновляются до текущего состояния (из-за этого нет возможности дописывать
    бэкап на dvd-r, например).

Incremental tar

Архиватор tar, который содержится в любом дистрибутиве, умеет делать
инкрементальные архивы, если указать опцию -g с указанием файла снапшота.

Примеры использования

Создаём полный бэкап домашней папки:
$tar -cvjf /backup/home.tar.bz2 -g /backup/home.snapshot -C /home/user/ .
Делаем следующий бэкап (например, через неделю):
$tar -cvjf /backup/home.1.tar.bz2 -g /backup/home.snapshot -C /home/user/ .
Первая команда создаёт стандартный архив tar и снапшот состояния файловой
системы на момент бэкапа. Вторая команда читает этот снапшот и архивирует только
изменённые файлы.
Желательно, создавать свой файл снапшота для каждого архива, т.к. он каждый раз
обновляется. Это позволит делать инкрементальный бэкап не только от предыдущего,
но и от первого архива, т.е. создать дифференциальный бэкап.

Недостатки

Существует один недостаток - это то, как tar определяет, какие файлы изменились.
Он проверяет файлы по inode, сверяет атрибуты файла, если они изменились, то
добавляет файл в архив. Вроде бы всё хорошо, но некоторые файловые системы имеют
свойство менять inode файлов для оптимизации или просто не имеют таковых, а ядро
при монтировании назначает каждый раз произвольные значения. Таким образом, при
изменении inode всех файлов, получается полный бэкап. Я с этим столкнулся на
файловой системе btrfs. Также вообще не получится сделать подобное на fat.

Tar + rdiff

Это такой гибридный способ на основе предыдущих, я стал его использовать в
последнее время. Принцип состоит в следующем:
Создание первого бэкапа:
  1. Создаём полный архив tar без сжатия:
    $tar -cvf backup.tar /home
  2. Создаём файл signature с помощью rdiff:
    $rdiff signature backup.tar backup.signature
  3. Архив можно сжать для экономии места.
Создание следующих бэкапов:
  1. Создаём полный архив tar без сжатия.
  2. Создаём файл signature с помощью rdiff для этого архива, например:
    $rdiff signature backup1.tar backup1.signature
  3. Создаём файл rdiff - разницу между предыдущим и текущим архивами:
    $rdiff delta backup.signature backup1.tar backup1.rdiff
  4. Можно удалить backup1.tar
Как видно, для создания инкрементального архива не требуется наличие первой
полной копии. Как восстановить последний архив:
$rdiff patch backup.tar bakup1.rdiff backup1.tar
Если бэкапов несколько, то восстановление осуществляется по цепочке.
Сжатие архива и создание сигнатуры для первого архива, а также создание разницы
и сигнатуры для последующих архивов можно выполнить за один шаг, не создавая
несжатые файлы с полным архивом, для этого можно использовать именованные
каналы. Привожу пример скрипта для архивации (для понятности добавил
комментарии):
#!/bin/bash
prefix=all
dt=`date +%Y-%m-%d`
srcsignature="$1"
#Проверка вида бэкапа
if [ -e "$srcsignature" -a -n "$srcsignature"]
then
    ext="rdiff.xz"
else
    ext="tar.xz"
fi
sourcefile=$prefix.$ext
endfile=$prefix.$dt.$ext
sourcesignature=$prefix.signature
endsignature=$prefix.$dt.signature

#Создаём именованные каналы
mkfifo for_signature for_delta

#Создание сигнатуры
rdiff signature for_signature $sourcesignature &
if [ -e "$srcsignature" -a -n "$srcsignature"]
then
    #Создание дельты
    rdiff delta $srcsignature for_delta | xz -zc > $sourcefile &
else
    #Сжатие полного архива
    xz -zc for_delta > $sourcefile &
fi

#Архивация (исправить для использования)
tar -cvf - -C ~/ \
scripts/ \
Документы/ \
Projects/ \
vimwiki/ \
.local/share/gnote/ |\
tee for_signature for_delta > /dev/null

#На всякий случай ждём окончания действий
sleep 10
sync
#Переименовываем файлы
mv $sourcefile $endfile
mv $sourcesignature $endsignature

#Удаляем каналы
rm for_signature for_delta
В качестве единственного параметра этого скрипта выступает файл сигнатуры
предыдущего бэкапа. Если файл не существует, или запуск производился без
параметров, делается полный бэкап. Сам список задаётся в команде tar, там же
можно указать опции архивации.
Есть один недостаток - архивирование выполняется долго, т.к. по сути создаётся
полный архив, но оно того стоит, т.к. в этом случае, в отличие от
инкрементального копирования средствами tar, получаются файлы меньшего размера.
Дело в том, что rdiff находит разницу между бинарными файлами, а в случае с
архивами - между содержанием архивов. Т.е. если изменится незначительно большой
файл, то при помощи rdiff будут записаны только изменения этого файла, а при
помощи tar будет перезаписан весь файл полностью.

Итог

Всё зависит от способа хранения резервных копий, если записывать инкрементальные
архивы на dvd-r, то подойдут 2 и 3 способы, а первый подойдёт только в случае
копирования на внешний винчестер или на другой компьютер по сети.
P.S.:
Кстати, rdiff-backup, использует rdiff для хранения изменений в файлах, хотя об
этом можно догадаться и из названия.
P.P.S.:
Библиотека rdiff также используется в rsync.

пятница, 16 мая 2014 г.

GTD с использованием vim

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

Однажды, я наткнулся на книгу Дэвида Аллена "Как привести дела в порядок" (ориг. "Getting things done" или GTD), которая многое поставила на свои места, но не сразу. Я не буду описывать здесь подробно систему GTD, с ней вы можете ознакомиться в вышеупомянутой книге. Дальнейшая информация предполагает некоторое знакомство с этой системой.

Для начала расскажу предысторию. Я не сразу начал пользоваться vim для этих целей, а использовал готовую утилиту для Gnome - GTG. Да, она удобна, интуитивна понятна и делает половину действий за пользователя. Последнее её достоинство оказалось самым большим недостатком, т.к. очень важной частью системы является анализ всей содержащейся в ней информации. Этот процесс должен производиться вручную, иначе куча дел просто зависнут в системе и вы перестанете обращать на них внимание, в дальнейшем она обрастёт множеством таких "зависших" дел, станет неэффективным, после чего вы перестанете её использовать. Поэтому, если и использовать подобные системы, нужно подходить к этому с умом и не надеяться, что программа всё упорядочит за вас.

Сам по себе vim не представляет собой удобное средство для системы, но используя некоторые плагины, можно сделать полноценную систему GTD. Один из таких плагинов -- vimwiki, который позволяет создавать списки с отметками о выполнении, перекрёстные ссылки между файлами с возможностью перехода, форматирование и прочее.

Использование системы

Итак, после установки vim и плагина для него, можно приступать к оформлению системы. Запускаем vim или графическую оболочку для него -- gvim, нажимаем вводим \ww, открывается начальная страница по умолчанию для vimwiki. Можно создать систему прямо начиная с начальной страницы, можно создать подстраницы. Я выбрал второе, т.к. использовал уже vimwiki для других целей, поэтому добавил следующее:

[[GTD|gtd/]]

Эта строчка является ссылкой на каталог gtd, по умолчанию будет произведён запуск средства для просмотра каталогов внутри vim, поэтому нужно дополнительно настроить использование vimwiki, но об этом позже.

Далее, в соответствии с GTD создадим подстраницы для отдельных списков (или в корне vimwiki, или внутри каталога gtd):

=GTD=

* [[inbox|Входящие]]
* [[current|Текущие действия]]
* [[projects/|Проекты]]
* [[../diary/diary|Запланированное]]
* [[someday/someday|Когда-нибудь, может быть]]
* [[../|База знаний]]
* [[waiting|В ожидании]]

Здесь первая строчка - это заголовок первого уровня, далее идёт маркированный список со ссылками на списки. Вообще структура системы может у вас отличаться от моей, т.к. тут уже каждый подстраивает систему под себя. Как видно, синтаксис vimwiki очень похож на markdown (почему бы разработчикам vimwiki не использовать markdown без изменений?).

Первая ссылка - это корзина, т.е. "Входящие" в терминологии GTD, сюда записываем всё, что необходимо сделать. В дальнейшем корзина входящих будет разбираться и сортироваться.

Следующая ссылка - список текущих действий, отсортированный по контексту. Примерная структура списка следующая:

=Общее=

=Звонки=

=За компьютером=

== Интернет ==

=По пути=

=На работе=

=Дома=

=Повестка дня=

Это лишь заголовки, под ними следует вставить списки дел, что можно сделать по разному, например, с использованием TODO-списков, их синтаксис похож на обычные списки, только добавляются квадратные скобки:

* [ ] Задание 1
* [o] Задание 2
    * [X] Подзадание 2.1
    * [ ] Подзадание 2.2
    * [ ] Подзадание 2.3
* [ ] Задание 3

Списки могут быть вложенные, выполнение одного задания можно отметить, нажав Ctrl-Space.

Далее в основном списке идёт ссылка на список проектов, я её вынес в отдельный каталог, чтоб не загромождать основной каталог системы. Структуру я описывать не буду, здесь можно сделать вложенные todo-списки или ссылки на страницы с проектами.

Следующая ссылка - запланированные дела, я использовал встроенную возможность vimwiki создавать ежедневные файлы. Файл со ссылками на ежедневные файлы по умолчанию находится в папке diary и называется соответственно. Помимо этого можно использовать плагин Calendar и соответствующую команду, введя которую, слева появляется окошко с календарём, в котором можно быстро перейти к нужному дню и создать/посмотреть список дел для конкретного дня.

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

Следующий пункт - справочная информация. Т.к. у меня первоначально vimwiki использовалась для хранения справочной информации, то в приведённом примере это ссылка на начальную страницу vimwiki.

Ну и последняя ссылка - список дел, выполнение которых ожидается от других людей или зависят от определённых событий. Просматривая этот список можно контролировать делегированные задания другим людям, и, по возможности, напоминать им о выполнении этих заданий.

Настройки vim

Чтобы было удобно пользоваться системой, нужно настроить vim, привожу пример своего файла настройки:

let g:vimwiki_use_mouse = 1
let g:vimwiki_folding = 1
let g:vimwiki_fold_lists = 1
let g:vimwiki_use_calendar = 1
let g:vimwiki_dir_link = 'index'
let g:vimwiki_browsers = ['firefox']
set textwidth=80

По порядку опишу опции:

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

  2. Использование складок. Скорее всего, список текущих дел будет слишком длинный и не будет умещаться на экране, использование складок позволить свернуть отдельные участки текста в соответствии с заголовками. Поэтому открыв список, вы будете видеть только заголовки, а введя zo складка будет открыта, и появится соответствующий список.

  3. Эта опция позволяет сворачивать не только заголовки, но и вложенные списки.

  4. Для того, чтобы правильно работала команда Calendar, нужно указать эту опцию.

  5. Везде ссылки на главную страницу каталога я заменял на ссылку на сам каталог, чтобы vim открывал не каталог, а заглавную страницу, нужна эта опция. В моём случае это index, т.е. при переходе по ссылке, например [[projects/]], будет произведён переход к файлу projects/index.wiki.

  6. Указывает программу для открытия интернет-ссылок.

  7. Ширина текста - это стандартная опция vim, которая форматирует текст по ширине во время ввода (см. справку vim).

Все остальные опции, которые касаются vim, у меня находятся в стандартном файле ~/.vimrc, это же отдельный файл, который я расположил в ~/.vimwiki.gvimrc, чтобы эти настройки активировались только при запуске vimwiki. Чтобы его задействовать и открыть сразу vimwiki, нужно запустить vim со следующими опциями:

gvim -U ~/.vimwiki.gvimrc -geometry 100x40+512+400 /home/vladimir/vimwiki/index.wiki

Тут я указал ещё размер окна gvim и его расположение. Можно создать кнопку запуска на рабочем столе и добавить туда эту команду. Чем проще получить доступ к системе, тем удобнее будет ей пользоваться, и тем больше вероятность, что вы действительно будете эффективно ей пользоваться.