Магия в zsh

November 4th, 2008

Захотелось мне в этот чудесный выходной понедельник поагитировать за свой любимый шелл. Чем, кстати, вообще может похвастаться какой-либо шелл, имея в конкурентах такого монстра, как 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.

SHELL, UNIX, tips , , ,

Чудеса!!

June 6th, 2008

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

Одна из таких: тетрис на sed’е. Это что-то невероятное!

p.s. да, и я тоже, оказывается, шаблонно мыслю :)

SHELL, Программирование , , ,

defun.ru – ресурс о функциональном программировании

April 11th, 2008

Не могу не пропиарить: www.defun.ru

Дефун это что-то типа Digg’а для людей интересующихся функциональным, декларативным и прочим “нестандартным” программированием.

(c) Semka

Основная тема — новости и ссылки о функциональном программировании, разных альтернативных и перспективных языках, ну и про computer science вообще. Ключевые слова — хаскель, erlang, lisp, smalltalk, ocaml. Ruby, groovy и питон туда тоже отлично впишутся.

Тру Программист

Там уже сейчас чтения на все выходные :)

общее

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

April 11th, 2008

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

#!/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>"

SHELL, UNIX, Программирование, загогулины ,

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

April 10th, 2008

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

Итак, к делу: регулярно, при записывании данных на диск, остается некоторое количество свободного места. Лет 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 # приводим в изначальный вид

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

UNIX, tips , , , ,

Сдал на MCSA!

April 1st, 2008

Это просто праздник какой-то, со второго раза удалось сдать оба экзамена на W2K3 MCSA – 70-290 и 70-291!
Если бы такие экзамены были у меня в университете, меня бы отчислили на первой же сессии, это единственное, что могу сказать. И еще, даже не ожидал, что они могут быть настолько сложны.

Но зато теперь я – Microsoft Certified System Administrator, урра!

Завтра мои данные появятся на https://mcp.microsoft.com/authenticate/validatemcp.aspx, id 7900401.

На очереди 70-297, даже не знаю, как я буду его сдавать.. :(
Но это потом, а пока – принимаю поздравления!

upd: смотрим на дату и больше не задаем глупых вопросов :)

общее

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

March 4th, 2008
“Бэкап – акт проявления трусости” (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?

SHELL, UNIX, tips , , ,

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

December 4th, 2007

Эта запись будет посвящена программе с лаконичным названием 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.

SHELL, UNIX, tips , ,

Первый опыт фриланса :)

November 17th, 2007

Три дня провел на getafreelancer.com

За это время успел сделать четыре заявки, выполнить один проект, заработать 35 баксов и, напоследок, составить некоторое мнение об этом сайте.

А именно, мне показалось, что можно заработать там тысячу-полторы денег, но на это нужно будет тратить большую часть свого времени и заниматься откровенной фигней. Собственно, это мой ответ на вопрос Сергея из города Донецка, который, похоже очень неплохо пропиарил GAF в России :)

Проектов для IT-специалистов на getafreelancer много, но 50% из них – это либо создание клонов (“i want clone of discussions.apple.com” – сделают за 95 баксов), либо заказы на спам и размещения ссылок, либо еще какая-нибудь муть.

Остальные 50% – это задачки на доработку скриптов – сделать какую-нибудь форму или поменять какой-нибудь шаблон. Есть задачки по написанию узкоспециализированных скриптов, иногда просят исправить глюки, совсем редко – поадминить сервер.

Свои 35 баксов я заработал, выполнив задачу “Found the reason for CPU Load”. На одном сервере процесс mysqld кушал 95% ресурсов процессора и владелец не мог понять, в чем дело. Мне пришлось на некоторое время включить логи MySQL чтобы обнаружить причину: какой-то дурацкий скрипт делал до 200 запросов к базе при каждом обращении к странице. Добавил индекс на два поля таблицы и нагрузка на CPU сразу же упала на 90% :) Предложил переписать так же и скрипт, но заказчик уже был удовлетворен результатом.

p.s. аффилиатных ссылок тут нет :)

общее

Загадка!

October 19th, 2007

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

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

#!/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

SHELL, UNIX, Программирование, загогулины , ,