Сергей Супрунов
IPython как инструмент системного администратора
Эффективность работы системного администратора во многом зависит от его умения автоматизировать свою работу. Традиционно для этого широко используется язык командной оболочки sh, а там, где его возможностей не хватает, применяют скриптовые языки – Perl, Python, Ruby... Но есть один инструмент, совмещающий в себе удобство командной оболочки и мощь скриптового языка – IPython.
Одним из преимуществ языка Python можно назвать интерактивный режим работы – набрав в командной строке «python» без параметров, вы увидите приглашение «>>>» и сможете, что называется, в режиме реального времени выполнять те или иные команды на языке Python. Этот режим оказывается очень удобным при разработке скриптов – можно проверить ту или иную идею, ознакомиться с доступными методами какого-нибудь объекта (функцией dir(obj)), или получить справку по какой-либо функции или модулю. Это делает язык Python достаточно удобным для системных администраторов при решении задач, где возможностей sh оказывается недостаточно. Но всё же одно небольшое неудобство остаётся – по-прежнему приходится «переключаться» между sh и Python, учитывая ограничения как первого, так и второго инструментов. А как же иногда хочется прямо из python получить листинг каталога, не прибегая к сложностям типа «os.listdir(os.curdir)», или же, наоборот, выполнить в sh привычный цикл «for i in range(5)» вместо того, чтобы мучительно вспоминать синтаксис цикла в bash... Возможно ли такое?
Вполне! Вы можете воспользоваться замечательной разработкой Фернандо Переза (Fernando Perez) – оболочкой IPython! На первый взгляд, это просто альтернатива стандартному интерактивному режиму работы Python, дополненная несколькими новыми возможностями. Но в этих нескольких дополнениях и заложено то «волшебство», которое делает IPython действительно уникальным инструментом.
Первое знакомство
В состав дистрибутивов операционных систем IPython обычно не включается, но найти её в стандартном репозитории наверняка труда не составит. Скажем, во FreeBSD IPython элементарно устанавливается из коллекции портов:
# cd /usr/ports/devel/ipython
# make install
Из зависимостей – только интерпретатор Python (версия 3.0 пока не поддерживается, но, думаю, это вопрос времени) и модуль pexpect. Также не лишней будет поддержка библиотеки readline (без неё не будут работать автодополнение, некоторые функции, связанные с историей команд). Ссылки приведены в конце статьи.
При первом запуске команды «ipython» оболочка попытается создать в домашнем каталоге пользователя подкаталог .ipython, в котором будут размещаться конфигурационные и рабочие файлы оболочки. В дальнейшем, при запуске оболочки вы будете получать подсказку по основным командам, позволяющим начать работу:
[amsand@pcbsd /usr/home/amsand]$ ipython
Python 2.5.2 (r252:60911, Sep 18 2008, 02:11:58)
Type "copyright", "credits" or "license" for more information.
IPython 0.8.4 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.
In [1]:
|
Здесь «In [N]:» – приглашение IPython, числа в квадратных скобках означают порядковый номер строки ввода. В дальнейшем вы увидите ещё и строки «Out [N]:» – это строки вывода. При желании эти приглашения можно изменить: в файле ~/.ipython/ipythonrc отредактируйте строки prompt_in1, prompt_in2 и prompt_out.
Всё, что вы могли делать в оболочке python, можно делать и здесь: импортировать модули, выполнять любые команды Python, пользоваться справочной системой. Но есть несколько дополнительных возможностей, которые и рассмотрим чуть подробнее.
Во-первых, это быстрый просмотр информации по тому или иному объекту (в том числе и встроенному):
In [18]: s = 'string'
In [19]: s?
Type: str
Base Class: <type 'str'>
String Form: string
Namespace: Interactive
Length: 6
Docstring:
str(object) -> string
Return a nice string representation of the object.
If the argument is a string, the return value is the same object.
In [20]:
|
То есть, добавив вопросительный знак к имени интересующего вас объекта, вы получите информацию о его типе, базовом классе, пространстве имён, а также строку документации объекта.
Во-вторых, это встроенные «магические» команды: alias, cd, pwd, pushd/popd и ряд других. Многие из них выполняют те же функции, к которым мы привыкли в командной оболочке. Некоторые специальные функции служат для расширения возможностей IPython. Но нужно учитывать, что если создать объект с таким же именем, то он перекроет встроенную команду:
In [31]: pwd
Out[31]: '/usr/home/amsand' |
In [32]: pwd = 12*3
In [33]: pwd
Поэтому основным синтаксисом встроенных команд является следующий: «%pwd», т.е. команда должна начинаться с символа «%». Это позволяет выполнить «магическую» функцию независимо от наличия «тёзок» в текущем адресном пространстве. Немного непривычно, но зато надёжно.
Кстати, IPython предоставляет мощные функции автодополнения команд – введите «%», нажмите клавишу <Tab> и вы получите полный список встроенных команд. Автодополнение действует почти везде, где оно имеет смысл. Например, вы можете получить список всех модулей, которые могут быть импортированы:
In [34]: import s <Tab>
scanext shelve smtpd sre_constants struct
sched shlex smtpd2 sre_parse subprocess
screen shutil smtplib stat sunau
select signal sndhdr statvfs sunaudio
sets sip socket string symbol
sgmllib sipconfig sqlite3 stringold symtable
sgmlop sipdistutils sre stringprep sys
sha site sre_compile strop syslog
|
Для любого объекта, введя его имя, точку и нажав <Tab>, вы получите список доступных атрибутов и методов. Автодополнение охотно предоставит вам список файлов в текущем каталоге там, где это может быть полезно (например, в команде open()). В общем, если вы будете активно использовать IPython, клавиша <Tab> станет одной из ваших любимых. (Впрочем, при желании вы можете её переопределить, поскольку её функциональность определяется библиотекой readline.)
Идём дальше. В-третьих, среди дополнительных возможностей нельзя не отметить упрощённый синтаксис вызова команд операционной системы. Если в стандартной оболочке python вам нужно было импортировать модуль os и прибегать к его функции system (например, «os.system('ps')»), то в IPython это сделать гораздо проще:
In [53]: !ps
PID TT STAT TIME COMMAND
11454 p0 Is 0:00,02 bash
35940 p0 S+ 0:00,58 /usr/local/bin/python2.5 /usr/local/bin/ipython
58841 p0 S+ 0:00,00 sh -c ps
58842 p0 R+ 0:00,00 ps
|
То есть вы можете выполнить любую системную команду прямо из IPython, просто предварив её символом «!». Опять-таки, не слишком привычно, но в любом случае на порядок удобнее, чем «скакать» между двумя терминалами.
В-четвёртых, IPython предоставляет мощнейший механизм истории команд. Помимо традиционной «стрелки вверх», позволяющей последовательно возвращаться к введённым ранее командам (которая, между прочим, ведёт себя в «csh-стиле», т.е. если ввести несколько символов и затем нажать стрелку вверх, «пролистываться» будут лишь команды, начинавшиеся с этих символов), вы можете воспользоваться встроенной командой %history, которая выведет пронумерованный список предыдущих команд (числом, переданным в качестве аргумента, можно ограничить количество выводимых строк). Ещё раз запустить любую из них очень просто: «_47» повторно исполнит 47-ю команду. Теперь, думаю, вы понимаете назначение чисел в квадратных скобках в приглашении.
Кстати, эти самые In и Out – самые настоящие (хотя и «особые») списки. Так что при желании вы можете обращаться к их элементам напрямую: «In[47]». Особенно полезен доступ к списку Out, позволяя повторно использовать вывод предыдущих команд:
In [66]: 3**2
In [67]: Out[66]/3
Вывод самой последней команды доступен как специальная переменная «_», так что предыдущий пример мог быть ещё короче:
In [66]: 3**2
In [67]: _/3
Помимо неё, можно использовать «__» и «___» (двойное и тройное подчёркивание) для доступа к предпоследнему и «пред-предпоследнему» выводу. Последние три введённые команды, помимо прямого обращения к In, доступны в переменных '_i', '_ii' и '_iii'.
Кстати, работа с историей команд «в стиле bash», т.е. через комбинацию клавиш <Ctrl> + <R>, тоже поддерживается. Так что своих привычек вам менять не придётся.
В-пятых, к командной строке утилиту IPython очень приближает поддержка псевдонимов. Управлять ими позволяет «магическая» команда %alias (можно и просто alias, если это имя не занято в текущем пространстве имён) – введённая без параметров, она выведет список кортежей вида «('псевдоним', 'системная команда')». В частности, именно благодаря псевдонимам вы можете применять в IPython такие часто используемые команды, как ls, mkdir, cp, rm, и тому подобные. Безо всяких восклицательных знаков!
Добавить псевдоним можно командой «%alias echo echo -n». Первый параметр – имя псевдонима (оно должно быть свободно в текущем пространстве имён), все последующие параметры рассматриваются как системная команда, которая будет выполнена при вызове псевдонима. Всё, что будет передано псевдониму как аргумент, просто допишется в конец системной команды.
Если же возникает необходимость вставлять параметры в середину команды, место вставки можно явно указать с помощью '%l' (маленькая L). Рассмотрим несколько искусственный пример: команда «alias lsvar ls %l /var/log» создаст псевдоним lsvar, выводящий листинг каталога /var/log, а в качестве параметра псевдониму можно будет передавать дополнительные опции утилиты ls. То есть «lsvar -l» будет трактоваться как «ls -l /var/log» – все параметры после lsvar будут подставлены вместо %l; возможности вставлять разные параметры в разные места команды я не нашёл.
В-шестых, при вызове различных функций и методов везде, где это не вызовет неоднозначности, можно опускать скобки. Более того, начав команду с запятой, вы сможете опустить и кавычки вокруг строковых параметров:
In [69]: ,open /etc/passwd r
------> open("/etc/passwd", "r")
Out[69]: <open file '/etc/passwd', mode 'r' at 0x28b67608>
|
И, наконец, отметим ещё один объект, который, собственно, и делает IPython такой, какая она есть. Это объект класса IPython.ipapi.IPApi: _ip. По сути, все синтаксические особенности IPython являются «обёртками» к методам этого объекта. «Магические» функции обрабатываются методом _ip.magic(), вызов системных команд – задача, выполняемая методом _ip.system(), и т. п. В чём вы можете убедиться, заглянув в историю команд – там отображается «низкоуровневая» функция, которая реально выполняется (вывод команд для краткости не приводится):
In [105]: %alias
In [106]: !date
In [107]: history 3
105: _ip.magic("alias ")
106: _ip.system("date")
107: _ip.magic("history ")
|
При желании вы можете непосредственно обращаться к методам _ip.
Все эти особенности (подробнее в документации) заметно приближают IPython по удобству работы к обычным командным оболочкам операционной системы. Но всё же некоторые «неудобства» остаются. Тем не менее и от них можно избавиться...
IPython как командная оболочка
Итак, как же можно ещё больше приблизить поведение IPython к поведению привычной нам командной оболочки? Как мы видели выше, существует один механизм, позволяющий выполнять системные команды непосредственно в IPython без необходимости использовать какие-либо дополнительные символы, – это псевдонимы.
Но, согласитесь, было бы весьма утомительно вручную создавать их хотя бы для основных системных команд. Однако есть две «магические» функции, %rehash и %rehashx, которые сделают за вас всю «чёрную» работу – они выполняют обход каталогов из переменной окружения $PATH и автоматически создают псевдонимы для всех найденных файлов. Отличаются они тем, что %rehashx создаёт псевдонимы только для файлов, которые текущий пользователь имеет право исполнять. Поэтому её использование предпочтительней, хотя она и выполняется несколько медленнее.
Чтобы каждый раз после входа в оболочку не заниматься её настройками под свои предпочтения, IPython поддерживает так называемые профили. Параметры профилей хранятся в каталоге .ipython в файлах ipythonrc-<имя_профиля>. Здесь можно задать вид приглашения командной строки, псевдонимы и прочие параметры. Запуск оболочки с поддержкой соответствующего профиля выполняется командой «ipython -p <имя_профиля>». Кстати, общие настройки оболочки можно найти в файле ipythonrc – не исключено, что вам захочется подправить что-то «глобально».
Однако наиболее удобным для запуска IPython в режиме командной оболочки представляется встроенный профиль sh. Запустите следующую команду: «ipython -p sh». В результате ipython запустится с более удобным приглашением (отображающим текущий каталог), автоматически выполнит функцию %rehashx, активирует расширение envpersist (которое сохраняет изменения переменных окружения между сессиями), а также наделит IPython некоторыми другими функциями, удобными именно в режиме командной оболочки.
Здесь, думаю, уместно пару слов сказать об одной из важнейших функций командной оболочки – перемещении по каталогам. Казалось бы, что здесь важного – «cd» в нужный каталог, и всё. Но когда в процессе работы постоянно приходится перемещаться между /usr/local/etc/apache, /var/log, /usr/home/www/public_html, /var/tmp и другими каталогами, то начинаешь вспоминать о таких вещах, как история команд, утилиты pushd/popd и т. п.
Так вот, помимо возможности использовать упомянутые выше инструменты, IPython предоставляет ещё несколько функций, заметно упрощающих перемещение по каталогам. Прежде всего это функция dhist:
[/usr~]|3> dhist
Directory history (kept in _dh)
0: /
1: /usr/home/amsand
2: /usr/home/amsand/.ipython
3: /usr/local/lib/python2.5/site-packages/IPython
4: /usr/ports
5: /usr/home/amsand
|
Это история перемещения по каталогам, использовать которую гораздо удобнее, чем общую историю команд – просто указываете в качестве параметра функции cd номер строки из истории и попадаете куда хочется:
[/usr~]|4> cd -2
Directory history (kept in _dh)
0: /
1: /usr/home/amsand
2: /usr/home/amsand/.ipython
3: /usr/local/lib/python2.5/site-packages/IPython
4: /usr/ports
5: /usr/home/amsand
|
Конечно, если вы умудритесь создать каталог с именем «-2», то так просто попасть в него не сможете. Как в bash (используя синтаксис «cd -- -2»), к сожалению, тоже не получится. Впрочем, у нас есть Python: «os.chdir('-2')» превосходно решит задачу.
Кстати, просто «cd -», как и в bash, вернёт вас в предыдущий каталог.
Ещё одна полезная «магическая» функция – %bookmark, позволяющая создавать «закладки» на часто посещаемые каталоги:
[usr~/.ipython]|9> bookmark lc /usr/local/etc
[usr~/.ipython]|10> cd -b lc
(bookmark:lc) -> /usr/local/etc |
Как видите, IPython почти ни в чём не уступает таким развитым командным оболочкам, как bash и csh. Даже без учёта её интеграции с языком Python она становится очень привлекательна для постоянного использования.
IPython и Python
Теперь самое интересное. Использовать IPython как интерактивную оболочку Python очень удобно. В качестве замены sh она тоже выглядит неплохо. Но разве нам кто-то может помешать совместить эти возможности?
Рассмотрим несколько примеров. Пусть стоит следующая задача – создать в текущем каталоге пустые файлы с расширениями txt и именами, соответствующими ряду простых чисел от 1 до некоторого заданного (например, 15). То есть нам нужно получить файлы 1.txt, 2.txt, 3.txt, 5.txt и т. д. Решить её можно так:
[usr~/itest]|29> def issimple(d):
|..> for i in xrange(2,d):
|..> if not d % i: return False
|..> return True
|..>
[usr~/itest]|30> for i in [i for i in range(1,15) if issimple(i)]:
|..> touch ${i}.txt
|..>
|..>
[usr~/itest]|31> ls
1.txt 11.txt 13.txt 2.txt 3.txt 5.txt 7.txt |
Согласитесь, что на bash такая задача решалась бы заметно сложнее. А здесь мы в полной мере смогли использовать мощь языка Python. Рассмотрим ещё один пример: периодически нужно считать, сколько строк, содержащих упоминание утилиты su, находится в логе /var/log/messages.
Для этого удобно использовать ещё один механизм IPython – макросы. Например, так:
[/usr~]|1> curdir = !pwd
[/usr~]|2> cd /var/log
[var/log]|3> cnt = !grep 'su:' messages | wc -l
[var/log]|4> print int(cnt[0])
[var/log]|5> cd $curdir[0]
[/usr~]|6> macro sucnt 1-5
Macro `sucnt` created. To execute, type its name (without quotes).
Macro contents:
curdir = !pwd
cd /var/log
cnt = !grep 'su:' messages | wc -l
print int(cnt[0])
cd $curdir[0]
|
[usr~]|7> sucnt
Macro `sucnt` created. To execute, type its name (without quotes).
Macro contents:
curdir = !pwd
cd /var/log
cnt = !grep 'su:' messages | wc -l
print int(cnt[0])
cd $curdir[0]
|
В первой строке (имеются в виду строки ввода) сохраняем в переменную curdir имя текущего каталога (если вызов системной утилиты используется не сам по себе, а в выражении на языке Python, то указывать символ «!» обязательно, иначе получите ошибку синтаксиса). Во второй переходим в /var/log (здесь можно без восклицательного знака). В третьей – сохраняем в переменную вывод двух объединённых в «конвейер» утилит. В четвёртой выводим его в виде числа (для оператора print это особого значения не имеет, я просто хотел показать, что это обычная переменная, над которой можно выполнять любые преобразования). Пятая строка возвращает нас в исходный каталог.
IPython в работе: вывод обратной трассировки тоже полезен
Конечно, здесь мы основную работу проделали силами системных утилит (в третьей строке), а не языка Python. Но в этом и преимущество IPython – можно выбирать любой удобный способ решения задачи. (В другом случае может оказаться проще обработать файл средствами Python, и ничто не помешает это сделать.) Ну а для повторного использования строки 1-5 сохраняем как макрос sucnt (строка 6; функция %macro выводит код созданного макроса, так что вы можете сразу же убедиться, что оболочка вас правильно поняла). Теперь, введя это имя, мы сможем повторно выполнить всю процедуру.
Обратите внимание, что по умолчанию макросы не сохраняются между сессиями – чтобы макрос можно было использовать и в будущем, следует явно сохранить его командой «store sucnt».
Если в макрос вам нужно будет внести изменения, не обязательно повторять всю процедуру заново – запустите команду 'edit sucnt', и вы получите возможность подправить код макроса в своём любимом текстовом редакторе. Только не забывайте, что при выходе из редактора макрос будет выполнен.
Кстати, команда edit (если точнее – %edit) предназначена не только для макросов – с её помощью вы можете редактировать подключённые модули, строки ввода и вывода (элементы In и Out соответственно), да и вообще любые блоки текста. Её можно использовать везде, где удобнее вбить в текстовом редакторе сразу несколько строк, чем выполнять их по одной.
Заключение
Как видите, IPython вполне может стать вашей основной командной оболочкой. Тесная интеграция с Python делает её очень мощным инструментом. И если вы активно пользуетесь этим скриптовым языком в своей работе, то возможность использовать привычные синтаксические конструкции также и для решения «административных» задач будет совсем не лишней.
Приложение
IPython в Windows
В системах Windows IPython тоже доступна и столь же прекрасно справляется с ролью основной командной оболочки (хотя, нужно признать, что в Windows это не самая популярная функция). А с учётом более развитых автодополнений, истории команд и функций навигации по каталогам она выглядит даже более предпочтительной. Только не забывайте устанавливать «привязку» pyreadline-1.5-win32-setup.exe (найти её можно на странице проекта – http://ipython.scipy.org/dist) – без неё многие «вкусности» останутся недоступными.
Другие оболочки
Если попытаться поискать другие интерактивные оболочки для языка Python, то можно найти ещё несколько проектов, которые будут полезны разработчикам, использующим этот язык. Например, система Reinteract (http://www.reinteract.org/trac) предоставляет возможность работать с Python в интерактивном режиме. В отличие от IPython и интерактивного режима интерпретатора здесь очень легко отправлять на выполнение целые блоки кода – набираете ваш код, как в обычном редакторе, для выполнения нажимаете <Ctrl> + <Enter>. Хотя меня, если честно, она не очень поразила.
Проект Leo (http://webpages.charter.net/edreamleo/front.html) очень интересен как среда разработки: помимо редактирования и отладки кода, его удобно использовать как менеджер проектов.
В среде Windows вам может понравиться работа с графической оболочкой IDLE (http://www.python.org/idle/doc/idlemain.html). По большому счёту, работа в ней мало чем отличается от работы в интерактивном режиме интерпретатора, но ряд дополнительных возможностей (загрузка и сохранение файлов, подсветка синтаксиса, более удобный доступ к документации) могут вам понравиться.
Однако найти инструмент, сравнимый с IPython по своим возможностям выполнять роль стандартной командной оболочки, позволяющей легко комбинировать программирование на Python с системными командами, мне не удалось.
- http://ipython.scipy.org – официальный сайт IPython.
- http://pexpect.sourceforge.net – страница разработки модуля pexpect.
- http://tiswww.case.edu/php/chet/readline/rltop.html – домашняя страница проекта GNU Readline Library.