Archive

Archive for the ‘Unix’ Category

Что делать с лишними клавишами на клавиатуре?

November 22nd, 2010 3 comments

На моей клавиатуре (Microsoft Natural) полно всяких кнопочек. Долгое время я их игнорировал, но недавно все-таки заставил их работать и дико доволен результатом.

microsoft natural

Для этого пришлось написать несколько скриптов, которые у меня живут в ~/quickscripts:

% ls -lh quickscripts
drwxr-xr-x   2 zed zed  39 2010-11-17 21:49 example
drwxr-xr-x   2 zed zed  39 2010-11-19 22:43 apache
lrwxrwxrwx   1 zed zed   6 2010-11-21 19:12 current -> apache
drwxr-xr-x   2 zed zed  28 2010-11-17 21:49 builder
-rwxr-xr-x   1 zed zed 269 2010-11-16 23:52 select-scripts
-rwxr-xr-x   1 zed zed 101 2010-11-19 19:53 show-current
% ls -lh current/
-rwxr-xr-x 1 zed zed 430 2010-11-19 22:43 cmdF
lrwxrwxrwx 1 zed zed   4 2010-11-17 20:55 cmd1 -> cmdF
lrwxrwxrwx 1 zed zed   4 2010-11-17 20:55 cmd2 -> cmdF

Вот какая за этим стоит идея: по дополнительным кнопкам вызываются скрипты ~/quickscripts/current/cmd{1,2,3}, где current – это симлинк на конкретный набор скриптов. Этих наборов несколько, каждый для какой-то отдельной задачи. Например, скрипты в директории apache вызывают /etc/init.d/apache2 reload|restart на разработческом сервере.

Чтобы выбрать конкретный набор скриптов я нажимаю на кнопку “5″:

Это окошко отображает скрипт select-scripts, он написан на kaptain + bash, вот как он выглядит:

#!/usr/bin/kaptain

start "Quickscript selector" -> dir @exec(script)="OK";

dir -> @list(`cd ~/quickscripts && ls | grep -vE 'select-scripts|current' `)=`cd ~/quickscripts && readlink current`;

script -> "cd ~/quickscripts && rm -f current && ln -s " dir " current";

Kaptain – удивительный по своей функциональности и лакончности фреймворк для создания несложных GUI, даже немного жаль, что нечасто возникает в этом необходимость.

Вот пример скрипта, по кнопке Favorites он выполняет какие-то рутинные действия на удаленном сервере, а по кнопке “1″ запрашивает аргумент через всплывающее окошко.

#!/bin/bash
id=`cat /tmp/task_id`
if [[ "`basename $0`" = 'cmdF' ]]; then
           cat > /tmp/r <<EOF
	     update BuildTasks set Log='', Status='waiting', Version='', Cancelled=0, RepositoryName='' where TaskID=$id
EOF
           a=`cat /tmp/r | ssh devserver 'killall builder </dev/null; mysql testdb' 2>&1 && echo "task $r was restarted"`
           rm /tmp/r
           notify-send -t 3000 'builder:' "$a"
else
           id=`zenity --entry --text="Task number" --entry-text="$id" || echo $id`
           echo $id > /tmp/task_id
fi

Результат работы отображается через libnotify:
kaptain dialog

В ubuntu для отображения уведомлений используется notify-osd, он всем хорош, но не поддерживает задание кастомных таймаутов (а по умолчанию – 10 секунд – это ужасно много), и не умеет отображать несколько уведомлений одновременно. Поэтому пришлось заменить его на старый вариант – notification-daemon, который поддерживает и то и другое:

apt-get remove notiy-osd
apt-get install notification-daemon

Осталось сказать, что запускать скрипты по нажатию на кнопку gnome умеет сам, и настраивается это в меню System->Preferences->Keyboard Shortcuts.

На этом все, буду рад, если кому-то мой опыт пригодится :)

Categories: Shell, Tips, Техноблог Tags:

Восхитительные грабли.

April 28th, 2010 13 comments

Я недавно открыл для себя восхитительные грабли. Оказывается, что я ходил по ним годами, а наступил только вчера.

Допустим, нам нужно скачать какой-нибудь файлик из сети, посчитать его размер и сохранить в файл.

Код на perl будет примерно таким:

#!/usr/bin/perl -w
use strict;

if (system('wget -O- http://sveshnikov.ru/httpd.sh | wc -с > /tmp/size') != 0) {
        die "OMG! Can't count bytes in httpd.sh file!!!";
}

В дальнейшем этот скрипт используется примерно так: if ./get_value; then работаем с /tmp/size; else сообщаем куда нужно; fi

Так вот, у этого скрипта хромает надежность. Почему? И как это сделать правильно? Жду ваших вариантов, мой – завтра :)

UPD:

Проблема заключается в том, что при использовании пайпов в $? окажется результат последней выполненной команды:

$ blablabla | wc; echo $?
zsh: command not found: blablabla
      0       0       0
0

Я решил этот вопрос с помощью bash и его опции pipefail. Пример выше я бы переписал как-то так:

#!/usr/bin/perl -w
use strict;                                                                                                                                                                    

sub my_system {
      return system('bash', '-o', 'pipefail', '-c', @_);
}                                                                                                                                                                              

unless (my_system('wget -O- http://sveshnikov.ru/httpd.sh | wc > /tmp/size') == 0) {
      die "OMG! Can't count bytes in httpd.sh file!!!";
}

Теперь будут отлавливаться все ошибки.
В шелл-скриптах можно еще анализировать массив PIPESTATUS, в котором сохраняется exit code для всех команд ковейера, но мне показалось, что это неудобно.

Debian-пакеты с человеческим лицом на примере Zabbix 1.9

March 29th, 2010 2 comments

Кросс-пост с хабрахабра, в котором я описываю пример сборки debian-пакета с использованием CDBS.

UPD от 8 января 2012 года: статью переписал примерно наполовину. Сделал ее понятнее и актуальнее. Теперь в ней идет речь про Zabbix 1.9.8 и Ubuntu 11.10

Написать эту статью меня заставили две вещи. Во-первых, возникла необходимость поставить Zabbix на сервере, работающем под ubuntu. Заббикс – прекрасная система мониторинга, единственный значительный минус которой в моих глазах – это катастрофически неудобный интерфейс. Впрочем, от версии к версии он становится все менее ужасным, поэтому я всегда ставлю не стабильную версию, а beta или RC.

Во-вторых, появилось стойкое ощущение, что после статей вида “делаем debian-пакет на коленке”, большинство хабражителей утвердятся во мнении, что debian-пакеты придумали извращенцы для извращенцев.

Связывает два этих события то, что zabbix 1.9 пока нет в репозиториях убунты, и в ближайшее время не появится, а делать configure && make && make install на продакшн-серверах, это, конечно, недостойное джентльмена занятие. В общем, появился хороший повод продемонстрировать, что debian-пакеты – это не страшно.

Итак, приступим:

1. Инициализация


apt-get install dh-make devscripts cdbs libmysqlclient-dev libcurl4-gnutls-dev
wget http://downloads.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Development/1.9.8/zabbix-1.9.8.tar.gz
tar zxvf zabbix-1.9.8.tar.gz
cd zabbix-1.9.8
dh_make -f ../zabbix-1.9.8.tar.gz --rulesformat cdbs --single

В результате будет создана дирекория zabbix-1.9.8/debian, с кучкой файлов внутри. Большинство из них нам не понадобится, и мы их удалим в конце, так что не пугайтесь :). Ключевую роль среди них играют 3-4 файла, ими мы и займемся.

Между делом, если бы мы пакетировали не zabbix, а более простую программу, которая обычно ставится с помощью ./configure; make; make install, то на этом создание пакета заканчивается. Осталось бы только собрать и установить пакет.

Но мы продолжим. Здесь и дальше я предполагаю, что вы находитесь в дирекории zabbix-1.9.8 (не в zabbix-1.9.8/debian).

2. Метаданные пакета.

Откроем файл debian/control и пропишем себя, любимого, в качестве создателя пакета, и укажем, какие пакеты должны приехать на сервер вместе с установкой zabbix. Для этого нужно найти строку ‘Depends’ (не путать с Build-Depends) и добавить в ее конец следующее: “fping, adduser, apache2, php5, php5-mysql, php5-gd”.

3. Выбор опций скрипта configure.

Обычно скрипт configure можно вызывать без параметров и он сгенерирует жизнеспособный конфиг, но для zabbix это не так – нужно отдельными опциями включать компиляцию серверной части и агента. Так как агент из репозитория ubuntu меня полностью устраивает, ограничимся сборкой только сервера. Для этого нужно дописать в конец файла debian/rules следующую строку:

DEB_CONFIGURE_USER_FLAGS := --enable-server --with-mysql --with-libcurl

4. Добавление файлов интерфейса в пакет.

Сборка пакета осуществляется следующим образом: создается временная директория (debian/имя_пакета), в которой в несколько этапов формируется его содержимое. Затем эта директория упаковывается в архив, добавляются метаданные, и все – пакет готов. Это очень грубое, но пока достаточное описание процесса. Бинарные файлы попадут в директорию debian/zabbix/usr/sbin сами собой (CDBS запустит команду make install DESTDIR=debian/zabbix), а про файлы php-интерфейса CDBS ничего не знает, поэтому нам придется указать на них самостоятельно. Для этого создадим файл debian/install вот с таким содержимым:

frontends/php/* usr/share/zabbix/
conf/zabbix_server.conf etc/zabbix

5. Создание пустых директорий.

Кроме того, для нормальной работы заббиксу нужны еще и директории для лог-файлов и локов. Они тоже являются частью пакета, поэтому создать их нужно прямо в той временной директории. Стандартный способ создания пустых директорий – перечисление их в файле debian/dirs:

/var/log/zabbix-server
/var/run/zabbix-server

6. Инит-скрипт.

В комплекте с заббиксом идет инит-сктипт (misc/init.d/debian/zabbix-server), но без обработки напильником он работать не будет. Поэтому лучше его заменить скриптом из убунты, который нужно сохранить под именем debian/init:


wget -O debian/init 'http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/oneiric/zabbix/oneiric/download/head:/zabbixservermysql.za-20090719032443-40a177i6799u0z76-876/zabbix-server-mysql.zabbix-server.init'

7. Logrotate.

Мы же труЪ-админы, а не халтурщики, поэтому создаем вот такой файл debian/logrotate:

/var/log/zabbix-server/zabbix_server.log {
daily
rotate 7
compress
missingok
notifempty
create 0640 zabbix zabbix
sharedscripts
}

О том, каким образом этот конфиг попадет в нужное место после установки пакета, думать не нужно :)

8*. Конфигурирование Apache, PHP и всего прочего

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

Итак, сконфигурируем веб-сервер:


mkdir misc/apache2-vhosts
cat > misc/apache2-vhosts/zabbix

ServerName zabbix
ServerAdmin admin@example.com
DocumentRoot /usr/share/zabbix
CustomLog /var/log/apache2/zabbix_access.log combined
ErrorLog /var/log/apache2/zabbix_error_log

^D
echo "misc/apache2-vhosts/zabbix etc/apache2/sites-available" >> debian/install

Затем займемся PHP:


mkdir misc/php.conf.d
cat > misc/php.conf.d/zabbix.ini
post_max_size = 16M
max_execution_time = 300
mbstring.func_overload = 2
max_input_time = 300
date.timezone = 'Europe/Moscow'
^D
echo "misc/php.conf.d/zabbix.ini etc/php5/apache2/conf.d" >> debian/install

И напоследок исправим в conf/zabbix_server.conf путь к лог-файлу (vim conf/zabbix_server.conf +39). Нужное нам значение: /var/log/zabbix-server/zabbix_server.log.

Можно подумать, что это было довольно бездумное решение – модифицировать исходный код пакета, поскольку это усложняет повторение процесса для следующей версии заббикса – нужно будет обязательно совершить эти правки еще раз.

К счастью, за нас об этом уже позаботились: после сборки пакета все внесенныые нами изменения (за пределами директории debian – т.е. в исходном коде софта), магическим образом появятся в директории debian/patches в виде патча. Поэтому все, что мы делаем с пакетом фактически сохраняется в директории debian.

9. Ручное вмешательство.

Иногда недостаточно просто разложить файлики по файловой системе, чтобы настроить среду для исполнения программы. В таких случаях на помощь приходят preinst, postinst, prerm и postrm скрипты, которые выполняются уже на сервере, куда пакет устанавливается. Названия у них вполне понятные, пояcнить нужно только то, что ‘inst’, и ‘rm’ – это фактическая распаковка или удаление содежимого пакета (все той же временной директории debian/zabbix, в нашем случае), кроме того – каждый из этих скриптов может вызываться с разными аргументами в зависимости от ситуации. Нам интересен скрипт postinst, вызывающийся с аргументом configure – нужное место скрипта можно легко найти в шаблоне postinst.ex. Приступим:


cd debian
mv postinst.ex postinst
vim postinst

Правим секцию configure:

...
configure)
# Создадим пользователя
useradd zabbix || echo "User zabbix was not added"

# Установим права на рабочие директории
chown zabbix:zabbix /var/log/zabbix-server /var/run/zabbix-server

# В этой директории веб-интерфейс пытается сохранить конфиг-файл, предоставим ему на это права:
chown www-data /usr/share/zabbix/conf
chmod 775 /usr/share/zabbix/conf

# Настроим автозапуск сервера:
update-rc.d zabbix defaults

# Включим новый virtualhost и перезапустим апач:
a2ensite zabbix
invoke-rc.d apache2 reload
;;

abort-upgrade|abort-remove|abort-deconfigure)

11*. Удаление ненужных шаблонов

В директории debian полно шаблонных конфигов и скриптов, которые нам на этот раз не пригодились:

rm debian/*.{ex,EX} debian/README.*

12. Сборка и установка.

Финишная прямая: запускаем сборку пакета командой debuild и, пропустив ругань на отсутствие электронной подписи мимо ушей, устанавливаем его командами:
dpkg -i ../package_name.deb
apt-get install -f

Это не очень красивый способ устанавливать пакет, но зато самый простой. Первая команда завершится с ошибкой, потому что dpkg не умеет самостоятельно устанавливать зависимости пакета. В результате пакет в системе останется, но будет в состоянии ‘broken’. Вторая команда все эти ошибки исправит. В случае, если все зависимости на месте, dpkg -i отработает без ошибок, и нужды во второй команде нет.

В завершении всего, можно выполнить команду debclean, чтобы удалить с диска все объектные файлы и временную директорию.

13*. Вышла новая версия Zabbix!

Распаковываем исходники, копируем директорию debian, выполняем инструкцию заново, начиная с 12-го шага.

Магия в zsh

November 4th, 2008 3 comments

Захотелось мне в этот чудесный выходной понедельник поагитировать за свой любимый шелл. Чем, кстати, вообще может похвастаться какой-либо шелл, имея в конкурентах такого монстра, как bash? Ведь в bash есть все, что может только пожелать обычный пользователь. А, собственно, и нечем. Поэтому разработчикам zsh пришлось пойти на хитрость и добавить в свое детище некоторое количество магии :)

Большая ее порция досталась подсистеме автодополнения. Вот таким можно сделать дополнение имен файлов:
zsh menu completion
(выбрать нужный вариант можно табом по старинке, курсорными клавишами или стандартными emacs-хоткеями)

А вот так – дополнение опций:

Еще одна моя любимая магическая штуковина в автодополнении выглядит так: допустим, нужно подправить файл /usr/local/etc/rc.d/mysql. Пользователь bash бы ввел такую команду:

vim /usr/l[TAB]/e[TAB]/r[TAB]/m[TAB]

В zsh все несколько проще, а именно:

vim /u/l/e/r/m[TAB]

После нажатия [TAB] все элементы пути будут дополнены. Если вариантов несколько, можно будет вручную выбрать нужный.

Ну вот, я вам передал примерно 0.65 процента магии zsh. Помимо автодополнения, ее залежи находятся в подсистеме подстановок (man zshexpn), но там я сам не очень уверенно ориентируюсь. Все-таки одна из прелестей zsh заключается в том, что мне необязательно учиться им пользоваться – для начала можно ограничиться только bash-совместимым подмножеством функций, регулярно натыкаясь на приятные мелочи в реализации привычных вещей.

Дальнейшее чтение:
обзор zsh от Алексея Федорчука,
Собрание хаков и идиом zsh: zsh lovers.

Categories: Shell, Tips, Unix, Техноблог Tags: ,

Пятничная загогулина (bash)

April 11th, 2008 15 comments

Ну вот, пришло время для очередной программерской загогулины. Следующий код работать не будет:

#!/usr/bin/bash
echo "one two three" | read a b c
echo "<$a> <$b> <$c>"

Что в нем не так?

Я ожидаю увидеть два ответа. Первый — это просто переписать этот код так, чтобы он заработал. И второй ответ — опционально — объяснение, почему не работает в таком виде.

p.s. второго ответа я пока сам не знаю, поэтому буду с интересом ждать его от вас :)
p.p.s. ответивший верно, как всегда – умничка (-ца (маловероятно)).

UPD: На второй вопрос ответ уже есть:
gds
есть мнение, что переменные, прочитанные read, остаются в переменных “экземпляра” баша, запущенного для выполнения “read a b c”, и не попадают в родительский баш, запустивший “echo … | read a b c”.

gds’у – респект!
А я понял, что в следующий раз надо постить задачки посложнее..

UPD2 свое решение выложу сегодня в конце рабочего дня
UPD3

Кажется, я нечаянно сорвал рабочий день моего начальника, но зато он мне прислал вот такое остроумное решение:
str=`echo "one two three" | (read a b c; echo "a=$a; b=$b; c=$c;") `
eval "$str";
echo "<$a> <$b> <$c>"

Петя, ты отжог :)

Но на самом деле все это можно сделать несколько проще – через “here doc”:
read a b c <<<`echo "one two three"`
echo "<$a> <$b> <$c>"

Заговор от битых кластеров (добавляем информацию для восстановления архивов с помощью par2)

April 10th, 2008 15 comments

В этой заметке я предложу способ чтения данных с поцарапанных, погрызанных собакой или обработанных шредером компакт-дисков.

Итак, к делу: регулярно, при записывании данных на диск, остается некоторое количество свободного места. Лет 5 назад можно было положить диск на полочку, пометив, что еще 30 мегабайт можно забить каким-нибудь хламом, но сейчас стоимость болванки – 10 рублей, такой аргумент не действует. И, соответственно, привычку оставлять место “на потом” надо искоренять. Мне кажется, наиболее разумным было бы добавить на диск данные для восстановления – т.н. корректирующие коды Рида-Соломона, которые могут пригодится в случае, если диск будет поврежден.

Собственно весь заговор выглядит следующим образом:
#sudo aptitude install par2
#man par2
#cd backups
#ls
dump.sql.gz
#par2 create -v -r10 -n1 -m500 dump.sql.gz
#ls
dump.sql.gz dump.sql.gz.par2 dump.sql.gz.vol000+100.par2

Эта команда добавит 10% избыточной информации к данным, запишет все это в один файл, при этом программе par2 разрешено использовать 500 мегабайт оперативной памяти. Файлы *.par2 следует записать на диск вместе с дампом.

Мне эта программа понравилась, я захотел ее проверить в боевых условиях. Сделал архив размером около 400 Мб, добавил данные для восстановления – еще 200Мб – *.par2 файлы (50% избыточность, по умолчанию – 5%). Все это я записал на CD-RW, в котором потом сделал, простите, дырку. В итоге стандартными средствами удавалось прочитать только первые 150 Кб данных. Чтобы восстановить файл нужно сначала все считать пускай с ошибками – для этого есть программа dd_rescue, которая является практчески полным аналогом dd с одним исключением – она умеет игнорировать ошибки чтения:

диск с дыркой

#sudo dd_rescue -Av -b 1048576 -B 1048576 /dev/scd0 brokencd.iso(-A – заполняь нулями те участки файла, которые считать не удалось, v – verbose, -b – размер блока данных, -B – размер блока данных для проблемных областей диска)
# sudo mount -o loop brokencd.iso mnt # монтируем получившийся образ диска
# cp mnt/* dump; cd dump # копируем содержимое
# par2 r archive.par2 # приводим в изначальный вид

На этом эксперимент завершился – все данные с диска восстановлены. Даже скучно.
Но пример, мне кажется, весьма красноречив :)

SSH для бэкапов и мониторинга: ограничиваем доступ.

March 4th, 2008 1 comment
“Бэкап – акт проявления трусости” (c) народная мудрость

Я труслив :) Во-первых, я делаю бэкапы. Во-вторых, я их боюсь передать без шифрования и, в третьих, иногда и храню их зашифрованными.

Как правильно организовать передачу бэкапов с одного сервера на другой? Дампы этого блога у меня передаются по http. Они зашифрованны, да и особо ценных данных здесь нет, поэтому http меня не смущает. А как поступить с данными по-важнее? Конечно, ssh. А как при этом запретить пользователю выполнять какие-либо действия, кроме как копирования к себе бэкапа? Представим себе, что бэкап-сервер находится во вражеском дата-центре или просто вы не можете проконтролировать к нему доступ (в т.ч. физический). Нас выручит опция command файла authorized_keys.

Например, если необходимо предоставить доступ только к файлу backup.tgz, то в authorized_keys в самом начале соответствующей строки можно дописать следующее “command=’cat backup.tgz’”. Теперь при каждом коннекте будет автоматически выполняться команда cat backup.tgz, вам остается только перенаправить вывод в файл. Если дампов несколько, то можно написать небольшой скриптик вида:#!/bin/sh
read file
case "$file" in
"foo") cat foo.tgz ;;
"bar") cat bar.tgz ;;
esac
И прописать его в качестве команды по умолчанию. Да, не лишним было бы добавить опции no-port-forwarding, no-pty и все прочие no-*

Теперь копировать файл с удаленной машины можно вот такой командой:echo "foo" | ssh backup@server > foo-`date +%Y-%m-%d`.tgz

Кроме как для бэкапов, такое же решение может подойти и для мониторинга. Когда нагиос стучится на удаленный сервер, чтобы собрать какую-либо статистику, полный ssh-доступ ему не нужен.

По-моему, все, что я описал примитивно по сложности и вместе с тем весьма надежно. Так может быть прекратим без надобности дописывать authorized_keys на серверах? Одна запись для себя, любимого, одна для бэкапов, одна для мониторинга.. ой, еще каких-то две.. дальше продолжать? :)

Кстати, а есть ли способы более тонко настраивать уровень доступа к ssh?

О прозрачности в командной строке [pv]

December 4th, 2007 4 comments

Эта запись будет посвящена программе с лаконичным названием pv. А слово “прозрачность” пусть не ассоциируется у вас с пресловутыми compiz-fusion, тут все гораздо интереснее :)

Итак, чем плох избитый пример c передачей файлов через netcat? Мне, например, не удобно то, что нет возможности наблюдать за процессом. В самом деле, возможности юниксовых шеллов в этом плане довольно скромные: с помощью tee можно сохранить поток в файл, который потом наблюдать через tail или следить за его размером командой ‘watch ls’. Этого достаточно для отладки, но мало для комфортной работы.

Поэтому программа pv просто не могла не появиться. Все очень в духе UNIX – маленькая утилитка, которая пропускает через себя поток данных и в STDERR отправляет некоторую статистику по ним. Но _как_ она это делает! Покажу на примерах:

Всегда хотел узнать:
dainichi@fujitsu:~$ cat /dev/toilet_paper | pv >/dev/shreder
1.01GB 0:00:02 [ 569MB/s] [ <=> ]

Ага, больше десяти рулонов в секунду..

Прикинемся взрослой программой с выводом а-ля wget:
dainichi@fujitsu:~$ cat file | pv -s `stat -c %s file` | nc so.far.away 1234
236kB 0:00:05 [ 346КB/s] [==================> ] 72%

Ограничим скорость обработки файла, чтобы mplayer не тормозил:
dainichi@fujitsu:~$ cat big_log | pv -L 100к | log_processor > report

Пример из мана – архивирование каталога и одновременное отображение прогрессбара
(tar cf - . | pv -n -s `du -sb . | awk '{print $1}'` \
| gzip -9 > out.tgz) 2>&1 | dialog --gauge 'Progress' 7 70

И, напоследок, скриншот с домашней страницы проекта:
скриншот с домашней странички проекта pv

Здорово? :) По-моему, да :)

Кстати. а какие еще способы “очеловечить” интерфейс командной строки вы знаете?

UPD Андрей Афанасенко поделился ссылкой вот на такое чудо:

Написана эта программа на bash и во многих случаях ее использовать гораздо удобнее, чем pv.

UPD от 19 ноября 2010: на IBM developers network появилась замечательная статья про пайпы в целом и PV в частности: Что внутри конвейера?

Загадка!

October 19th, 2007 9 comments

“Если достаточно долго лазить по карманам своих курток, можно найти практически любую сумму денег” (народная мудрость). Вот и с задачками примерно такая же ситуация – вспомнил весьма любопытную.
Приятно, знаете ли, иногда посмотреть как люди мучаются над задачками, которые когда-то серьезно озаботили тебя самого :)

Итак, есть следующий код:

#!/bin/sh

get_size() {
if [ "`uname`" = "FreeBSD" ]; then
r=`stat -f %z $1`
else
r=`stat -c %s $1`
fi
return $r
}

if [ -z $1 ]; then
echo "usage: print_size ";
else
get_size $1;
echo $?
fi

Вот результат работы скрипта:
asveshnikov@fe08a023fb1cc27a:~/tmp$ ls -la
total 112
drwxr-xr-x 2 asveshnikov asveshnikov 4096 2007-10-19 15:38 .
drwxr-xr-x 85 asveshnikov asveshnikov 8192 2007-10-19 13:15 ..
-rw-r--r-- 1 asveshnikov asveshnikov 39781 2007-08-29 15:22 DSC02473.jpg
-rw-r--r-- 1 asveshnikov asveshnikov 49553 2007-08-31 17:41 DSC02481.jpg
-rwxr-xr-x 1 asveshnikov asveshnikov 231 2007-10-19 15:27 print_size.sh
asveshnikov@fe08a023fb1cc27a:~/tmp$ ./print_size.sh print_size.sh
231
asveshnikov@fe08a023fb1cc27a:~/tmp$ ./print_size.sh DSC02473.jpg
39781

Как видите, абсолютно рабочий код, проверялся в Linux и FreeBSD.
При этом он имеет просто ужасную.. нет, чудовищную проблему переносимости, которую при некоторых обстоятельствах крайне сложно обнаружить в скриптах несколько большего размера – какую?

p.s. угадавший первым будет умничкой :)

UPD:

Уже двое человек указали на то, что `uname` желательно взять еще и в кавычки. Вобщем, предлагаю не мелочиться, здесь проблема если и есть, то явно не “чудовищная”. Чтобы больше никого не смущать этим, подправил код.

Решено!

Михаил достаточно подробно описал проблему:

Если не брать в голову отсутствие кавычек вокруг $1, а также неполный способ определения размера файла (под солярой нет stat, например), то мне кажется основная проблема в возврате значения из функции. На самом деле таким образом можно вернуть только целое, причем очень ограниченное, так как по сути возвращается код завершения функции (если не изменяет память – максимум – 256). таким образом на больших файлах получим неверное значение.

Решением может служить использование для возврата глобальное переменной, либо через echo.

С моей стороны осталось лишь пояснить, почему проблема является “чудовищной” – она запросто может привести к порче данных, так как никакие сообщения об ошибках выводиться не будут. Ну и выглядит внешне этот код вполне надежным, так что отлавливать такой баг может быть задачей не из легких.

Собственно, основные проблемы возникают при портировании скрипта с sh на bash:

asveshnikov@fe08a023fb1cc27a:~/tmp$ ls -al DSC02473.jpg
-rw-r--r-- 1 asveshnikov asveshnikov 39781 2007-08-29 15:22 DSC02473.jpg
asveshnikov@fe08a023fb1cc27a:~/tmp$ bash print_size.sh DSC02473.jpg
101

Kubuntu 7.10 && Enlightenment 0.17

October 19th, 2007 2 comments

Смешанные чувства: нет эйфории, которая была с 7.04: просто прервал работу на полчаса, поставил новую систему, добавил с десяток нужных мне пакетов и продолжил работу.

И уже в процессе работы стал натыкаться на приятные мелочи: dolphin, который действительно мне показался шагом вперед в плане юзабельности, KNetworkManager, в котором появилось окошко статуса, strigi – служба полнотекстового поиска по локальным файлам, и еще опера, которая теперь доступна из ‘Canonical partner’ – репозитория.

Хм. Да вроде бы и все.

Куда больше интересного произошло на работе: нам выдали по второму монитору и видеокарте, и я пару часов потратил на приятнейшие хлопоты с подключением-настройкой всего этого добра. Выяснилось, правда, что по-нормальному со вторым монитором (в режиме xinerama) не работает ни одна из привычных мне систем: в KDE просто не получилось на него вывести никакой полезной информации, в enlightenment 0.16 обнаружился неприятный глюк – смазывался текст при манипуляциях с окнами. Наверняка все заработало бы в режиме TwinView или MergedFB, но у меня вторая видеокарта – старая ATI под слот PCI, поэтому другого варианта не было.

скриншот с офсайта
Искать счастья я стал в e17, и.. нашел!! Я в полном восторге от нее! Все, чем мне нравился e16 там осталось, но как плюс – красивые темы, полноценная панель управления, гениальнейший диалог быстрого запуска, плагины и сносная поддержка xinerarma.

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

Все равно, в итоге я от самых простых вещей теперь тащусь, как удав по стекловате!!

Categories: Unix, Техноблог Tags: ,