<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Bappoy&#039;s blog &#187; debian</title>
	<atom:link href="http://bappoy.pp.ru/tag/debian/feed" rel="self" type="application/rss+xml" />
	<link>http://bappoy.pp.ru</link>
	<description>Линуксоид на велосипеде с моторчиком</description>
	<lastBuildDate>Fri, 02 Dec 2011 11:44:47 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Пакетная система Debian: низкоуровневая работа с deb-пакетами</title>
		<link>http://bappoy.pp.ru/2010/10/22/low-level-deb.html</link>
		<comments>http://bappoy.pp.ru/2010/10/22/low-level-deb.html#comments</comments>
		<pubDate>Fri, 22 Oct 2010 12:30:30 +0000</pubDate>
		<dc:creator>bappoy</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[deb]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[dpkg]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://bappoy.pp.ru/?p=945</guid>
		<description><![CDATA[<h2>Формат deb-пакета</h2>
<p>Краеугольный камень пакетной системы Debian — это deb-пакет (см. <a href="http://www.opennet.ru/man.shtml?topic=deb&#038;category=5&#038;russian=2">deb(5)</a>), представляющий из себя архив формата <a href="http://sourceware.org/binutils/docs-2.20/binutils/ar.html#ar">ar</a>, внутри которого содержится три файла:<br />
1. debian-binary — текстовый файл, содержащий версию формата deb-пакета, в данный момент это 2.0. Программы, работающие с deb-пакетами, должны читать только первую строку этого файла и не падать, если минорная версия вдруг поменяется (например, станет 2.1).<br />
2. control.tar.gz — служебная информация о пакете, скрипты, вспомогательные файлы (см deb-control(5)). Должен содержать только файлы, единственная папка, которая может присутствовать&nbsp;— &laquo;.&raquo; (текущая директория). В этот архив обязательно должен входить файл control, его минимальное содержимое рассмотрим чуть ниже.<br />
3. data.tar — собственно файлы, устанавливаемые в систему.  Чаще всего этот файл сжат каким-нибудь архиватором (поддерживаются расширения .gz, .xz, .bz2, .lzma), чаще всего в архивах встречается data.tar.gz.<br />
<!--more--><br />
Указанный порядок следования файлов в архиве обязателен. Если в этом архиве требуется разместить еще какие-нибудь файлы (не представляю, зачем это может кому-нибудь понадобиться), они должны находиться перед data.tar.gz, т.е. последний файл в архиве всегда data.tar. Но если сообщество когда-нибудь решит добавить в формат deb еще файлы, они будут помещены после data.tar.</p>
<p>Файл control в архиве control.tar.gz описывает назначение, версию и зависимости пакета, его формат более-менее подробно описан в <a href="http://www.opennet.ru/man.shtml?topic=deb-control&#038;russian=2">deb-control(5)</a>. Пересказывать всю справку сейчас не буду, опишу лишь минимальное содержимое, необходимое для взаимодействия с инфраструктурой dpkg:</p>
<pre>Package: имя пакета
Version: строка версии (при выборе политики назначения версий следует придерживаться <a href="http://manpages.debian.net/cgi-bin/man.cgi?query=deb-version&#038;sektion=&#038;apropos=0&#038;manpath=Debian%205.0%20lenny">deb-version(5)</a>)
Maintainer: John Doe &lt;johndoe@foo.com&gt; (человек, поддерживающий пакет, а не автор программы)
Description: короткое описание пакета
 Длинное описание,  на несколько строк. Каждая строка, входящая в
 длинное описание,  должна начинаться с пробела</pre>
<h2>Работа с пакетами средствами ar</h2>
<p>Теоретически данной информации должно быть достаточно, чтобы собрать простейший пакет &laquo;на коленке&raquo; и установить его в систему. Пусть наш пакет (назовем его test) просто добавляет в систему  файл /usr/share/example-content/test со строчкой &laquo;test&raquo;. Сделаем архив data.tar.gz со структурой папок и единственным файлом, а также файлик debian-binary:</p>
<pre>$ <strong>mkdir -p usr/share/example-content/</strong>
$<strong> echo test &gt; usr/share/example-content/test</strong>
$<strong> tar czf data.tar.gz usr</strong>
$ <strong>echo 2.0 &gt; debian-binary</strong></pre>
<p>Создадим файл <code>control</code> со следующим содержанием:</p>
<pre>$ <strong>cat control</strong>
Package: test
Version: 1.0
Maintainer: Dummy Maint &lt;dummy@example.org&gt;
Description: test package
 Test package created on my own knees.
$ tar czf control.tar.gz control</pre>
<p>Теперь соберем все воедино:</p>
<pre>$ <strong>ar -qS test-1.0.deb debian-binary control.tar.gz data.tar.gz</strong></pre>
<p>В текущем каталоге должен появиться файл <code>test-1.0.deb</code>. Его &laquo;физическое&raquo; содержимое можно просмотреть  с помощью следующей команды:</p>
<pre>$ <strong>ar t test-1.0.deb</strong>
debian-binary
control.tar.gz
data.tar.gz</pre>
<p>Посмотреть файл debian-binary:</p>
<pre>$ <strong>ar p test-1.0.deb debian-binary</strong>
2.0</pre>
<p>Посмотреть список файлов в пакете:</p>
<pre>$ <strong>ar p test-1.0.deb data.tar.gz|tar -tzf -</strong>
usr/
usr/share/
usr/share/example-content/
usr/share/example-content/test</pre>
<p>Посмотреть содержимое файла control:</p>
<pre>$<strong> ar p test-1.0.deb control.tar.gz |tar -O -xzf - control</strong>
Package: test
Version: 1.0
Maintainer: Dummy Maint &lt;dummy@example.org&gt;
Description: test package
 Test package created on my own knees.</pre>
<p>Можно установить этот пакет и убедиться, что файл <code>/usr/share/example-content/test</code> успешно создан, но лучше этого не делать, поскольку из-за недостатка информации в control в пакетной системе может появиться мусор:</p>
<pre>$ <strong>sudo dpkg -i test-1.0.deb</strong>
Selecting previously deselected package test.
(Reading database ... 97631 files and directories currently installed.)
Unpacking test (from test-1.0.deb) ...
Setting up test (1.0) ...</pre>
<h2>Работа с пакетами средствами dpkg-deb</h2>
<p>Все вышеописанное позволяет управляться с deb-пакетами на самом низком уровне, не имея под рукой ничего, кроме стандартных средств Unix (доподлинно известно, что программа ar входила в состав первых Unix 1970х годов). Однако, как несложно догадаться, есть и более высокоуровневые способы создания пакетов и изучения их содержимого. В частности, если уж так необходимо поковыряться с пакетом на низком уровне, все вышеописанные действия настоятельно рекомендуется выполнять с помощью утилиты dpkg-deb(1).</p>
<h3>Создание пакета средствами dpkg-deb</h3>
<p>Минимальный формат вызова команды dpkg-deb для построения пакета следующий:</p>
<pre><strong>dpkg-deb -b исходная_папка</strong></pre>
<p>Все, что находится в исходной папке, кроме директории DEBIAN, помещается в data.tar.gz. Содержимое DEBIAN будет использовано для создания control.tar.gz, в частности, будет прочитан и проанализирован файл control и в случае каких-либо ошибок (отсутствует одно из необходимых полей или эти поля имеют неправильные значения) пакет просто не будет создан. Процесс создания нашего тестового пакета с нуля теперь выглядит так (в последней команде предполагается, что в текущей папке остался файл control от сборки пакета средствами ar):</p>
<p>Подготовка структуры:</p>
<pre><strong>$ mkdir -p test-1.1/usr/share/example-content/ test-1.1/DEBIAN</strong>
$ <strong>echo test 1.1 &gt; test-1.1/usr/share/example-content/test</strong>
$ <strong>sed 's/Version: 1.0/Version: 1.1/g' control &gt; test-1.1/DEBIAN/control</strong></pre>
<p>Попытаемся собрать пакет:</p>
<pre>$ <strong>dpkg-deb -b test-1.1</strong>
warning, in file 'test-1.1/DEBIAN/control' near line 5 package 'test':
 missing architecture
dpkg-deb: building package `test' in `test-1.1.deb'.
dpkg-deb: warning: ignoring 1 warnings about the control file(s)</pre>
<p>Несмотря на отсутствие важного, но не необходимого поля Architecture, был создан пакет test-1.1.deb. Добавим поле и пересоздадим пакет:</p>
<pre>$ <strong>sed -i "1a \
Architecture: all" test-1.1/DEBIAN/control</strong>
$ <strong>dpkg-deb -b test-1.1</strong>
dpkg-deb: building package `test' in `test-1.1.deb'</pre>
<p>Еще одна немаловажная деталь. Как правило, в названии файла пакета указывается его архитектура, а команда <code>dpkg-deb -b</code> назвала файл по имени папки, из которой он был создан. Если бы папка называлась ololo, то мы получили бы ololo.deb. Чтобы файл пакета автоматически именовался в формате имя-версия-архитектура, при вызове dpkg -b необходимо указывать папку, куда будет положен итоговый архив, например, текущую. Тогда все компоненты имени файла будут извлечены из control:</p>
<pre>$ cp -R test-1.1 ololo
$ dpkg -b ololo
dpkg-deb: building package `test' in `ololo.deb'.
$ dpkg -b ololo .
dpkg-deb: building package `test' in `./test_1.1_all.deb'.</pre>
<p>Теперь всё относительно нормально, продолжаем изучение возможностей dpkg-deb на примере нового пакета.</p>
<h3>Получение информации о пакете</h3>
<p>Узнать версию формата deb, размер пакета и содержимое файла control:</p>
<pre>$ dpkg -I test_1.1_all.deb
 new debian package, version 2.0.
 size 644 bytes: control archive= 259 bytes.
     160 bytes,     6 lines      control
 Package: test
 Architecture: all
 Version: 1.1
 Maintainer: Dummy Maint &lt;dummy@example.org&gt;
 Description: test package
  Test package created on my own knees.</pre>
<p>Список файлов, устанавливаемых в систему (кроме служебных):</p>
<pre>$ dpkg -c test_1.1_all.deb
drwxr-xr-x bvk/bvk           0 2010-10-22 13:21 ./
drwxr-xr-x bvk/bvk           0 2010-10-22 13:21 ./usr/
drwxr-xr-x bvk/bvk           0 2010-10-22 13:21 ./usr/share/
drwxr-xr-x bvk/bvk           0 2010-10-22 13:21 ./usr/share/example-content/
-rw-r--r-- bvk/bvk           9 2010-10-22 13:21 ./usr/share/example-content/test</pre>
<p>Обратите внимание на владельца устанавливаемых файлов и каталогов: это не root, а некий пользователь. Чтобы исправить эту проблему, можно собирать пакеты из-под root&#8217;а, либо воспользоваться специальной утилитой <code>fakeroot</code> из одноименного пакета. Она перехватывает системные вызовы <code>chmod(2)</code> и<code> stat(2)</code> для файлов, и возвращает значения, как если бы файл принадлежал пользователю root. Небольшой пример:</p>
<pre>$ <strong>id</strong>
uid=1000(bvk) gid=1000(bvk) ...
$<strong> touch trololo</strong>
$ <strong>ls -l trololo</strong>
-rw-r--r-- 1 bvk bvk 0 2010-10-22 13:23 trololo
$ <strong>fakeroot ls -l trololo </strong>
-rw-r--r-- 1 root root 0 2010-10-22 13:23 trololo</pre>
<p>Думаю, принцип понятен. Пересоберем пакет еще более правильно:</p>
<pre>$ <strong>fakeroot dpkg -b test-1.1 .</strong>
dpkg-deb: building package `test' in `test_1.1_all.deb'.
$ <strong>dpkg -c test_1.1_all.deb</strong>
drwxr-xr-x root/root         0 2010-10-22 13:25 ./
drwxr-xr-x root/root         0 2010-10-22 13:25 ./usr/
drwxr-xr-x root/root         0 2010-10-22 13:25 ./usr/share/
drwxr-xr-x root/root         0 2010-10-22 13:25 ./usr/share/example-content/
-rw-r--r-- root/root         9 2010-10-22 13:25 ./usr/share/example-content/test</pre>
<p>Теперь наконец ок.</p>
<p>Можно получаить информацию о пакете в заданном формате:</p>
<pre>$ <strong>dpkg-deb -W --showformat='${Package}-${Version}-${Architecture} (${Maintainer})\n' </strong>test_1.1_all.deb
test-1.1-all (Dummy Maint &lt;dummy@example.org&gt;)</pre>
<p>Список полей, которые можно указать в &#8211;showformat, можно узнать из вывода команды <code>dpkg-deb -I</code></p>
<p>Подать на STDOUT архив data.tar.gz из пакета (уже &laquo;разжатый&raquo;), может быть полезно для извлечения только некоторых файлов:</p>
<pre>$ <strong>dpkg-deb --fsys-tarfile test-1.0.deb |tar -Ox usr/share/example-content/test</strong>
test</pre>
<h2>Перепаковка пакета</h2>
<p>Пожалуй, теперь наступил момент применить свежеполученные знания на практике :) Часто возникает следующая проблема: из некоего источника поступил пакет с некорректными зависимостями, например, требуется устаревший пакет, отсутствующий в системе и всех репозиториях, но доподлинно известно, что другой, уже установленный пакет предоставляет нужную функциональность. В скачанном пакете требуется изменить файл control, убрав или исправив зависимость. Правильно было бы скачать и распаковать исходник пакета (apt-get source), произвести необходимые изменения в скриптах сборки, установить все необходимые для пересборки библиотеки и окружение и т.д. и т.п., но для частного использования (т.е. без распространения по репозиториям) достаточно просто распаковать пакет, изменить необходимые файлы и запаковать обратно. Проиллюстрирую последовательность действий на примере невинного пакета hello:</p>
<pre>$ <strong>aptitude download hello</strong>
Get:1 http://yum.fireground.ru/ubuntu/mirror/ maverick/main hello i386 2.5-1 [34.4kB]
Fetched 34.4kB in 0s (824kB/s)
# да-да, я сижу под убунтой и описываю debian
# распаковать содержимое пакета в папку hello (если не существует, будет создана):
$ <strong>dpkg-deb -x hello_2.5-1_i386.deb hello</strong>
# распаковать содержимое control.tar.gz в hello/DEBIAN
$ <strong>dpkg-deb -e hello_2.5-1_i386.deb hello/DEBIAN</strong>
# что-нибудь поменять в control, например, версию пакета:
$ <strong>sed -i 's/Version: .*$/Version: 2.5-1test/' hello/DEBIAN/control </strong>
# собрать новый пакет:
$ <strong>fakeroot dpkg -b hello/ .</strong>
dpkg-deb: warning: 'hello//DEBIAN/control' contains user-defined field 'Original-Maintainer'
dpkg-deb: building package `hello' in `./hello_2.5-1test_i386.deb'.
dpkg-deb: warning: ignoring 1 warnings about the control file(s)</pre>
<p>Пакет собран. Убедиться, в том, что  в нем нет ошибок из-за немного нетрадиционного способа сборки, можно с помощью программы lintian:</p>
<pre>$ <strong>sudo aptitude install lintian</strong>
...
$ <strong>lintian hello_2.5-1test_i386.deb</strong>
$ <strong>echo $?</strong>
0</pre>
<p>Всё в порядке!</p>
<p>Об установке пакетов в систему, механизме зависимостей, структуре репозиториев и еще более правильных способах сборки пакетов читайте в следующих статьях :)</p>
]]></description>
		<wfw:commentRss>http://bappoy.pp.ru/2010/10/22/low-level-deb.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Шпаргалка по созданию chroot-окружения в Debian средствами debootstrap</title>
		<link>http://bappoy.pp.ru/2010/01/20/debian-chroot.html</link>
		<comments>http://bappoy.pp.ru/2010/01/20/debian-chroot.html#comments</comments>
		<pubDate>Wed, 20 Jan 2010 10:49:45 +0000</pubDate>
		<dc:creator>bappoy</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[chroot]]></category>
		<category><![CDATA[debian]]></category>

		<guid isPermaLink="false">http://bappoy.pp.ru/?p=845</guid>
		<description><![CDATA[<p>Для тестирования различных версий нашего продукта (внутри — БД под управлением mysql и интерфейс к ней на PHP под Apache2)  требуется быстро создавать многочисленные chroot-окружения на выделенном сервере и управляться с ними. </p>
<p>В базовой системе (lenny) оставляем только функционал, необходимый для управления всем хозяйством, лично мне необходимы mc, openssh, vim, bash_completion и иногда svn. Также неплохо поиметь где-нибудь (да хоть на этой же машине) кэширующий прокси для репозиториев debian, типа <a href="http://apt-proxy.sourceforge.net/">apt-proxy</a> или <a href="http://www.nick-andrew.net/projects/apt-cacher/">apt-cacher</a>, чтобы не создавать излишнюю нагрузку на региональные зеркала. У нас используется apt-cacher, работающий по адресу http://apt:3142.</p>
<p><a href="http://wiki.debian.org/Debootstrap">Debootstrap</a> ­— основная рабочая лошадка:</p>
<pre>apt-get install debootstrap</pre>
<pre>debootstrap --include=mc,ssh,vim lenny /systems/lenny http://apt:3142/ftp.debian.org/debian/</pre>
<p>Первый аргумент — название релиза, второй — путь, куда устанавливается система, третий — адрес репозитория. В опции &#8211;include через запятую указываются пакеты, которые необходимы, но не входят в минимальную базовую систему. Debootstrap выкачивает из репозитория и устанавливает минимальный набор пакетов, теоретически сразу после этого можно делать chroot /systems/lenny и переходить к работе, но осталась еще несколько немаловажных доделок:</p>
<p>Добавляем идентификатор системы, который будет отображаться в скобках в приглашении шелла (читай — bash), выполняемом в chroot-окружении:</p>
<pre>echo lenny > /systems/lenny/etc/debian_chroot</pre>
<p>Но работа в основном ведется от имени root, а в squeeze и sid у root&#8217;а в .bashrc переменная окружения PS1 переопределяется и этот идентификатор пропадает. Поэтому если делаем виртуалку squeeze, то строчку с PS1 в /root/.bashrc лучше закомментировать:</p>
<pre>sed -i 's/^\(export PS1.*\)$/#\1/g' /systems/<b><font color="red">squeeze</font></b>/root/.bashrc</pre>
<p>Монтируем /dev/pts — виртуальную файловую систему, которая динамически создаёт файлы терминалов /dev/pts/X для каждого нового подключения; это необходимо для нормального функционирования многих программ, работающих с терминалом, в т.ч. скриптов postinst и config пакета mysql-server:</p>
<pre>mount -t devpts devpts /systems/lenny/dev/pts</pre>
<p>Монтируем /proc (реально proc в новом месте будет содержать ту же информацию, что и общесистемный /proc):</p>
<pre>mount -t proc proc /systems/lenny/proc</pre>
<p>Чтобы apt-get не ругался на неподписанные пакеты при установке, необходимо обновить файл Release.gpg, т.к. по умолчанию debootstrap его не устанавливает. Это проще всего сделать обновлением индексных файлов репозитория:</p>
<pre>chroot /systems/lenny apt-get update</pre>
<p>После этого уже можно делать <code>chroot /systems/lenny</code>, устанавливать и настраивать пакеты, запускать/останавливать сервисы и т.д. Главная проблема при этом ­— следить за тем, чтобы сервисы в разных chroot&#8217;ах не конфликтовали, пытаясь занять порт на одном IP-адресе. Обычно добавляются виртуальные сетевые интерфейсы и им назначаются виртуальные же IP-адреса, которые и указываются в настройках сервисов.</p>
<p>Disclaimer: данная заметка описывает мой персональный опыт и не претендует на полноту. Комментарии и дополнения приветствуются.</p>
]]></description>
		<wfw:commentRss>http://bappoy.pp.ru/2010/01/20/debian-chroot.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Угадывание мыслей и выполнение несуществующих команд средствами bash</title>
		<link>http://bappoy.pp.ru/2008/11/17/quick-call-ssh.html</link>
		<comments>http://bappoy.pp.ru/2008/11/17/quick-call-ssh.html#comments</comments>
		<pubDate>Mon, 17 Nov 2008 06:33:44 +0000</pubDate>
		<dc:creator>bappoy</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://bappoy.pp.ru/?p=336</guid>
		<description><![CDATA[<p>В Debian в bash был добавлен патч, благодаря которому пользователь может написать свою функцию, выполняемую в случае, если введённая пользователем команда отсутствует. В Ubuntu эту фичу использует подсказка command-not-found, заметно тормозящая работу, в то время как можно найти более интересные и полезные возможности применения этого механизма,  оставив поиск пакета специализированным программам. Поделюсь своим опытом.</p>
<p>У нашего подразделения есть специальная сеть для тестовых серверов и виртуальных машин: 192.168.20.0/24, и очень часто приходится набирать команды типа <code>ssh user@192.168.20.xx</code>, причем в командах различается только последняя цифра. У ограниченного числа серверов нужно указывать другой <code>username</code>. Реже приходится ходить на сервера в других подсетях (в пределах 192.168.0.0/16); также иногда клиенты открывают нам доступ к своим системам, чтобы мы смогли продиагностировать их проблему и решить ее на месте.</p>
<p>Как следует из предыдущего абзаца, очень часто набираются команды вида:</p>
<pre>ssh ordinary_user@192.168.20.xx
ssh special_user@192.168.xx.yy
ssh third_user@ww.xx.yy.zz</pre>
<p>Возникает естественное желание этот процесс сократить и оптимизировать. Когда серверов было немного, я насоздавал множество <a href="http://bappoy.pp.ru/2007/11/21/konsole-encodings.html">хитрых алиасов</a> вроде следующего:</p>
<pre>alias 123='ssh user@192.168.20.123'</pre>
<p>Однако вскоре я понял, что поддерживать список из полусотни alias&#8217;ов — не true unix way, и задумался об альтернативах. Вспомнил об опытах вебмастеров эпохи web 1.0 по использованию 404 ошибки для отображения страницы с нужным содержанием, задумался о том, каким образом bash перехватывает вызов неизвестной команды и подменяет её командой поиска нужного пакета&#8230; В результате беглого изучения состава пакета command-not-found было выяснено, что используется функция <code>command_not_found_handle</code>. Она принимает в качестве аргумента введённую пользователем команду, выполняет некие действия и возвращает 127, если ничего нельзя сделать (в таком случае bash выводит стандартное сообщение об ошибке), или любое другое число, если что-то получилось.</p>
<p>Остальное оказалось делом техники. В <code>~/.bashrc</code> была добавлена функция:</p>
<pre>command_not_found_handle () {
    if [[ ! "$1" ]] ; then
        return 127
    fi

    n="$1"

    if echo $n| perl -ne 'exit(/^([1-9]|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/ ? 0:1)' ; then
        ip=192.168.20.$n
    elif echo $n| perl -ne 'exit (/^([1-9]|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.([1-9]|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/ ? 0:1)' ; then
        ip=192.168.$n
    elif echo $n| perl -ne 'exit (/^([1-9]|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.([1-9]|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.([1-9]|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.([1-9]|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/ ? 0:1)' ; then
        ip=$n
    else
        return 127
    fi

    ssh $ip
}
</pre>
<p>Любое введённое число от 1 до 255 преобразуется в команду <code>ssh 192.168.20.число</code>; два числа — в <code>ssh 192.168.число.число</code>; любой введённый IP-адрес превращается в <code>ssh IP-адрес</code>. Во всех остальных случаях просто выводится сообщение <code>"command not found"</code>.</p>
<p>Поскольку используется довольно сложное регулярное выражение, то для его обработки пришлось использовать perl. Ещё был вариант с <code>grep -qP</code>, но эксперименальная опция <code>-P</code> (расширенная поддержка perl-овых регулярных выражений) включена в grep не во всех дистрибутивах (например, в Ubuntu 8.04 её нет, а в 8.10 уже есть).</p>
<p>Чтобы для всех хостов в 20 сети подставлялось общее имя пользователя ordinary_user, а для избранных хостов — специальные имена, в ~/.ssh/config я добавил строчки (общие параметры для всех хостов, предваряемые конструкцией <code>Host *</code>, должны находиться в конце списка):</p>
<pre>Host 192.168.20.251
User special_user1

Host 192.168.20.252
User special_user2

Host 192.168.20.254
User special_user3

Host *
User ordinary_user</pre>
<p>К сожалению, мне не удалось заставить эту функцию обрабатывать также и параметры командной строки: функции command_not_found_handle передаётся только первый позиционный параметр, остальные недоступны. Поэтому для каждого нестандартного хоста придётся либо писать полный вариант команды со всеми параметрами, либо указывать настройки сервера в ~/.ssh/config, подобно указанным выше. Имеются и прочие недостатки в реализации, обсуждаемые, в частности, на сайте <a href="http://smylers.hates-software.com/2008/01/04/090399e2.html">smylers hates software</a>.</p>
<p>Однако даже с такими ограничениями открываются новые потрясающие возможности.  Думаю, что предложенное мной применение не единственное, и этот пост — не последний на данную тему.</p>
<p>P.S. бонус для дочитавших до этого места: <a href="http://regexlib.com/">библиотека регулярных выражений perl</a>, где я нашел регэксп для проверки строки на соответствие IP-адресу.</p>
]]></description>
		<wfw:commentRss>http://bappoy.pp.ru/2008/11/17/quick-call-ssh.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

