Skip to content

Home Администрирование Командная оболочка UNIX
Командная оболочка UNIX

У работы в командной оболочке UNIX есть свои преимущества (из которых можно назвать унифицированный подход к решению проблем, богатый набор инструментов, достаточно краткий и простой синтаксис, стандартные потоки ввода-вывода, конвейеры и перенаправление), но для нас было бы просто замечательно добавить этому старому другу еще и возможности Python. Оболочка IPython обладает рядом особенностей, которые повышают ценность соединения этих двух оболочек.

alias

Первая особенность объединения оболочки Python/UNIX, которую мы рассмотрим, - это специальная функция alias. С помощью этой функ-

ции можно создавать сокращенные псевдонимы системных команд. Чтобы определить псевдоним, достаточно просто ввести имя функции alias и далее указать системную команду (с любыми допустимыми параметрами). Например:

Существует несколько способов передать дополнительные данные на вход псевдонима. Один из них - пассивный подход. Если все, что требуется передать псевдониму, допустимо смешивать в одну кучу, такой подход может оказаться полезным. Например, если с помощью утилиты grep из результатов команды netstat, показанных выше, необходимо отобрать только те, где номер порта равен 80, можно выполнить такую команду:

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

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

Здесь используется синтаксическая конструкция %l (знак процента, за которым следует символ «l»), которая вставляет оставшуюся часть командной строки в псевдоним. В реальной жизни такой прием, скорее

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

И вот вам пример пассивного подхода, переделанный так, чтобы явно обрабатывать все дополнительные аргументы:

В действительности, в этом примере не требовалось добавлять конструкцию %1. Если ее опустить, результат не изменится.

Для вставки параметров в середину командной строки можно было бы использовать параметр подстановки строки %s. Следующий пример демонстрирует, как выполняется обработка параметров:

Однако здесь может возникнуть проблема. Если псевдониму, который ожидает получить два параметра, передать только один, можно ждать появление ошибки:

С другой стороны, вполне безопасно можно передавать большее число параметров:

Параметры foo и bar были помещены в соответствующие позиции, а параметр bam просто был добавлен в конец, чего и следовало ожидать.

Сохранить псевдоним можно с помощью специальной функции %store, и ниже В этом разделе будет показано, как это делается. Продолжая предыдущий пример, мы можем сохранить псевдоним achoo, чтобы при следующем запуске оболочки IPython его можно было использовать:

Выполнение системных команд

Другой и, пожалуй, более простой способ выполнения системных команд заключается в использовании восклицательного знака (!) перед ними:

Имеется возможность передавать системным командам значения переменных, при этом имена переменных должны начинаться со знака доллара ($). Например:

Здесь перечислены все сеансы работы с командной оболочкой bash, принадлежащие пользователю jmjones.

Ниже приводится пример сохранения результатов команды !:

Обратите внимание, что результат работы команды, сохраненный в переменной 1, отличается от результата, полученного в предыдущем примере. Это потому, что переменная 1 содержит объект списка, тогда как в предыдущем примере демонстрировался обычный вывод команды. Подробнее объекты списков мы будем рассматривать в разделе «Обработка строк».

Альтернативой использованию символа ! является использование комбинации ! !. Эта комбинация обеспечивает возможность выполнять те же самые действия, что и !, за исключением того, что не позволяет сохранять результат в переменной. Но при ее использовании открывается возможность использовать конструкции _ и _[0-9]*, которые будут обсуждаться ниже, в разделе «История результатов».

Использование ! или !! перед системными командами определенно составляет меньше труда, чем создание псевдонимов, однако в одних случаях более предпочтительными могут оказаться псевдонимы, а в других - использование ! или !!. Например, если предполагается, что некоторая команда будет использоваться постоянно, лучше создать для нее псевдоним. Для однократного или очень редкого использования лучше применять ! или !!.

rehash

Существует еще один способ создания псевдонимов и/или выполнения системных команд из оболочки IPython, основанный на применении специальной функции rehash (выполняющей рехеширование). С технической точки зрения, она создает псевдонимы системных команд, но не совсем так, как это делали бы вы сами. Специальная функция rehash дополняет «таблицу псевдонимов» всем, что будет обнаружено в пути поиска файлов, определяемым переменной окружения PATH. Вы можете спросить: «Что это за таблица псевдонимов?». Когда создаются псевдонимы, оболочка IPython отображает имена псевдонимов на системные команды, с которыми они должны быть ассоциированы. Таблица псевдонимов как раз и описывает эти отображения.

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

Эта таблица выглядит как словарь:

Во время работы оболочка IPython предоставляет в ваше распоряже
ние ряд переменных, таких как In и Out, с которыми мы уже встреча
лись ранее. Одна из таких переменных называется______ IP. Она представ
ляет собой объект интерактивной оболочки. Атрибут этого объекта,
с именем alias_table, ссылается на эту таблицу. Это именно то место,
где хранятся отображения имен псевдонимов на системные команды.
Мы можем просматривать эту таблицу точно так же, как любую дру
гую переменную:

После вызова функции rehash объем словаря значительно увеличился:

Вид может оказаться обманчивым, но это не тот случай. В настоящий момент в этом словаре имеется 16 элементов:

Попробуем отыскать в нем то, чего не было прежде, но что должно было появиться, — теперь в словаре должна появиться утилита transcode:

Когда вам встречается имя переменной или атрибута, начи
нающееся с двух символов подчеркивания (____ ), как правило,

это означает, что программист не предполагал, что вы будете
изменять содержимое этой переменной. Мы обратились к пе
ременной _ IP, но только для того, чтобы продемонстрировать

вам внутреннее устройство. В случае необходимости мы могли бы воспользоваться официальным прикладным интерфейсом (API) IPython и обратиться к объекту _ip, доступному из командной строки оболочки IPython.

rehashx

Специальная функция rehashx по своему действию напоминает специальную функцию rehash, за исключением того, что при просмотре каталогов, перечисленных в переменной окружения PATH, она добавляет в таблицу псевдонимов только имена исполняемых файлов. Поэтому резонно предположить, что сразу после запуска оболочки IPython в результате работы функции rehashx таблица псевдонимов будет иметь тот же или меньший объем, как после запуска функции rehash:

Интересно: после запуска функции rehashx размер таблицы псевдонимов оказался на семь элементов меньше, чем после вызова функции rehash. Ниже приводятся эти семь отличий:

И если поинтересоваться, почему, например, файл rmmod.modutils был отобран функцией rehash, но не был отобран функцией rehashx, можно обнаружить следующее:

Здесь видно, что rmmod.utils - это ссылка на insmod.modutils, но ins-mod, modutils отсутствует на диске.

cd

Если вам приходилось работать в стандартной оболочке Python, то, возможно, вы заметили, что в ней достаточно сложно определить имя каталога, в котором вы находитесь. Можно использовать функцию os.chdir(), чтобы перейти в нужный каталог, но это не очень удобно. Имя текущего каталога можно узнать с помощью функции os.get-cwd(), но это тоже крайне неудобно. Поскольку в стандартной оболочке Python выполняются команды языка Python, это может выглядеть не такой большой проблемой, но при работе в оболочке IPython и наличии более простого доступа к системным командам достаточно важно иметь возможность более простого перемещения по каталогам.

Попробуйте воспользоваться специальной функцией cd. Вам кажется, что мы придаем этому большее значение, чем оно заслуживает: здесь нет ничего революционного и вполне можно обойтись без этой функции. Но только представьте, что ее нет. Жизнь без нее оказалась бы намного сложнее.

В оболочке IPython функция cd работает практически так же, как одноименная команда Bash. Типичный пример ее использования: cd directory_name. Этого вполне можно было ожидать из опыта работы в Bash. При вызове без аргументов функция cd выполняет переход в домашний каталог пользователя. Если после имени функции добавить пробел и дефис, cd -, она выполнит переход в предыдущий каталог. Функция cd может принимать три дополнительных аргумента, которые отсутствуют у одноименной команды в Bash.

Указание аргумента -q запрещает IPython вывод имени каталога /tmp, в который был выполнен переход.

Первый аргумент: -q, или quiet. Если этот аргумент не указать, IPython будет выводить имя каталога, куда был выполнен переход. В следующем примере демонстрируются способы изменения текущего каталога как с применением аргумента - q, так и без него:

Еще одной особенностью функции cd в IPython является возможность перехода по определенным ранее закладкам. (Вскоре мы объясним, как они создаются.) В следующем примере показано, как выполнить переход в каталог по созданной ранее закладке:

В этом примере предполагается, что ранее для каталога /imp была создана закладка с именем t. Формально синтаксис перехода в каталог по закладке имеет следующий вид: cd -b bookmark_name, но если закладка bookmark_name определена и в текущем каталоге отсутствует подкаталог bookmark_пате, то ключ -b можно опустить - в этом случае оболочка IPython предполагает, что вы собираетесь выполнить переход по закладке.

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

В первой части примера приводится список ранее посещавшихся каталогов. Как его получить, мы совсем скоро расскажем. Затем следует вызов функции cd, которой передается числовой аргумент -6. Он сообщает оболочке IPython, что нам требуется перейти в каталог, который находится в списке под номером «6», то есть в каталог /home/jmjones/ local/tmp. И в последней строке оболочка сообщает, что теперь вы находитесь в каталоге /home/jmjones/local/tmp.

bookmark

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

ее, закладки будут восстановлены. Создать закладку можно двумя способами. Ниже демонстрируется первый из них:

Выполнив команду bookmark t после перехода в каталог /tmp, мы создали закладку с именем t, указывающую на каталог /tmp. Второй способ создания закладки требует ввести более чем одно слово:

Здесь была создана закладка с именем muzak, которая указывает на локальный каталог с музыкой. Первый аргумент - это имя закладки, а второй - имя каталога, на который ссылается закладка.

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

Вместо команды bookmark -1 можно использовать команду cd -b:

Удалять закладки можно двумя способами: удалить сразу все закладки или только выбранную. В следующем примере создается новая закладка, затем она удаляется, а после этого удаляются все остальные закладки:

Нажав несколько раз клавишу Backspace, продолжим с того места, где остановились:

В этом примере сначала была создана закладка с именем ulb, указывающая на каталог /'usr/'local/bin. Затем она была удалена с помощью аргумента -d bookmark_name команды bookmark. В конце были удалены все закладки с помощью аргумента -г.

dhist

В примере использования функции cd был продемонстрирован список посещавшихся ранее каталогов. Этот список сохраняется не только в течение сеанса, но и между сеансами работы с оболочкой IPython. Ниже демонстрируется пример вызова функции dhist без аргументов:

Быстро получить доступ к этому списку можно с помощью команды cd -<TAB>, как показано ниже:

Две дополнительных возможности функции dhist делают ее более гибкой, чем команда cd -<TAB>. В первом случае имеется возможность указать, сколько каталогов должно быть отображено. Например, чтобы указать, что требуется отобразить только пять последних посещавшихся каталогов, можно воспользоваться такой командой:

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

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

pwd

Это простая функция, но она часто бывает необходима при навигации в дереве каталогов. Функция pwd выводит имя текущего каталога. Например:

Подстановка переменных

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

Это достаточно надуманный пример. Едва ли вам потребуется создать 10 текстовых файлов, каждый из которых содержит дату. Но этот пример наглядно демонстрирует, как смешивать программный код на языке Python с программным кодом на языке командной оболочки. В этом примере выполняются итерации по списку, созданному функцией range(), каждый элемент которого поочередно сохраняется в переменной i. В каждой итерации с использованием нотации ! вызывается системная утилита date. Обратите внимание, что синтаксис вызова date идентичен способу, который использовался бы, если бы мы определили переменную окружения i. При таком подходе производится вызов утилиты date, а ее вывод перенаправляется в файл с именем {текущий элемент cnucкa).txt. После этого в примере выводится список созданных файлов и даже содержимое одного из них, чтобы убедиться, что он содержит нечто, напоминающее дату.

В системную оболочку можно передавать любые значения, полученные в Python. Независимо от того, получены эти значения из базы данных, созданы в ходе вычислений, получены в результате обращения к службе XMLRPC или извлечены из текстового файла, вы можете получить их средствами языка Python и передать системной команде, применяя прием с использованием !.

Обработка строк

Другой невероятно мощной особенностью, которую предлагает оболочка IPython, является возможность обрабатывать строки, полученные от системных команд. Предположим, что нам необходимо получить идентификаторы всех процессов (PID), принадлежащих пользователю jmjones. Для этого можно было бы использовать следующую команду:

Эта команда выглядит достаточно компактной и понятной. Но попробуем решить ту же самую задачу средствами IPython. Для начала получим вывод от команды ps aux:

Результат работы команды ps aux сохраняется в переменной ps в виде списка, элементами которого являются строки, полученные от системной команды. Под словами «в виде списка» в данном случае подразумевается, что переменная принадлежит к встроенному типу list, поэтому она поддерживает все методы, принадлежащие этому типу. Благодаря этому, если у вас имеется функция, которая ожидает получить список, вы можете передать ей полученный объект с результатами. Кроме того, помимо стандартных методов списка она поддерживает

еще пару весьма интересных методов и один атрибут, которые могут вам пригодиться. Только ради того, чтобы продемонстрировать эти «интересные методы», мы пока отложим задачу получения всех процессов, принадлежащих пользователю jmjones. Первый «интересный метод» - это метод grep(). Фактически он представляет собой обычный фильтр, который определяет, какие строки оставить, а какие отбросить. Чтобы узнать, имеются ли какие-нибудь строки, содержащие слово lighthttp, мы могли бы воспользоваться следующей командой:

Здесь мы вызвали метод grep() и передали ему регулярное выражение 'lighthttp'. Запомните: регулярные выражения, которые передаются методу gгер(), не чувствительны к регистру символов. В результате этого вызова метода grep() была получена строка, где было найдено соответствие регулярному выражению 'lighthttp'. Чтобы получить все записи, за исключением тех, что соответствуют указанному регулярному выражению, мы могли бы использовать примерно такую команду:

Мы передали методу grep() регулярное выражение 'Mar07' и обнаружили, что большинство процессов было запущено 7 марта, поэтому мы решили получить все процессы, которые были запущены не 7 марта. Чтобы исключить все записи, соответствующие регулярному выражению 'Mar07', мы добавили еще один аргумент: prune=True. Этот именованный аргумент сообщает оболочке IPython, что «любые записи, соответствующие указанному регулярному выражению, должны быть отброшены». И, как видите, в полученном списке нет ни одной записи, соответствующей регулярному выражению ' Mar07'.

С методом grep() можно также использовать функции обратного вызова. Это означает, что метод grep() может принимать в виде аргумента функцию и вызывать ее. Он передает функции текущий элемент списка. Если функция возвращает True для этого элемента, он включается в итоговый набор. Например, мы могли бы получить содержимое каталога и оставить в нем только файлы или только каталоги:

Этот каталог содержит «файлы». Мы не можем сказать, какие из них действительно являются файлами, а какие каталогами, но если воспользоваться фильтром os. path. isfile(), мы сможем отобрать только те, которые являются файлами:

В этом списке отсутствует «файл» code, следовательно, он вообще не является файлом. Попробуем отобрать каталоги:

Теперь видно, что code действительно является каталогом. Другой интересный метод - это метод fields(). После (или даже до) того, как будет выполнена фильтрация набора результатов в соответствии с определенными требованиями, вы можете отобразить те поля, которые желательно было бы вывести. Вернемся к нашему предыдущему примеру, где выводились записи о процессах, запущенных не 7 марта, и выведем только информацию в полях USER, PID и START:

Во-первых, обратите внимание, что метод fields() применяется к результатам, возвращаемым методом grep(). Это возможно потому, что метод дгер() возвращает объект того же типа, что и объект ps. Метод

fields() так же возвращает объект того же типа, что и метод grep(). Благодаря этому мы смогли объединить в цепочку методы grep() и f ields(). Теперь подробнее о том, что здесь происходит. Метод f ields() принимает неопределенное число аргументов, которые, как предполагается, обозначают номера «колонок» в выводе, при этом предполагается, что колонки отделяются пробелами. Это очень похоже на то, как awk разбивает строки текста. В данном случае методу fields() предписывается вывести колонки с порядковыми номерами О, 1 и 8. Эти номера соответствуют колонкам USER, PID и START.

Теперь вернемся к задаче отображения идентификаторов всех процессов (PID), принадлежащих пользователю jmjones:

В этом примере сначала отбираются только первые два столбца, 0 и 1, которые соответствуют колонкам USER и PID, соответственно. Затем из полученного списка, с помощью метода grep(), отбираются только те записи, которые соответствуют регулярному выражению 'jmjones'. И в заключение, из полученного набора выводится только второе поле с помощью вызова метода fields(1). (He забывайте, что нумерация полей начинается с нуля.)

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

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

список в виде строки можно было сохранить в переменной с именем pids и затем в оболочке IPython выполнить, например, такую команду: kill $pids. Но такая команда послала бы сигнал SIGTERM всем процессам, принадлежащим пользователю jmjones, что привело бы к завершению работы текстового редактора и сеанса IPython.

Ранее уже демонстрировалось, что та же самая задача может быть решена с помощью однострочного сценария на языке awk:

Мы будем готовы добиться тех же результатов после того, как рассмотрим еще одну концепцию. Метод grep() принимает еще один необязательный параметр с именем field. Если параметр field определен, во время принятия решения о включении очередного элемента в результат критерий поиска будет применяться к указанному полю:

В этом случае были отобраны требуемые строки, но они были получены целиком. Чтобы отобрать только идентификаторы процессов, можно предусмотреть следующее действие:

Теперь мы имеем средства достичь той же цели, что и фильтр на языке

awk.

Профиль sh

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

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

Профиль sh (или shell) - это один из встроенных профилей IPython. Профиль sh определяет значения некоторых конфигурационных параметров, в результате чего оболочка IPython становится более дружественной по отношению к системной командной оболочке. Приведем два примера параметров конфигурации, имеющих значения, отличные от значений в стандартном профиле IPython: параметр, задающий отображение текущего каталога в строке приглашения к вводу, и параметр, задающий рехеширование каталогов, перечисленных в переменной окружения PATH, что обеспечивает моментальный доступ ко всем исполняемым файлам, к которым он имеется, например, в оболочке Bash.

Помимо установки некоторых конфигурационных значений профиль sh активирует некоторые полезные расширения. Например, он активирует расширение envpersist. Расширение envpersist позволяет изменять различные переменные окружения и запоминать их значения в профиле sh, благодаря чему ликвидируется необходимость обновлять содержимое файла .bash_profile или .bashrc.

Теперь добавим : /appended в конец значения переменной PATH:

Теперь посмотрим содержимое переменной PATH с помощью os. environ:

Ниже показано, как выглядит значение переменной PATH:

Закроем оболочку IPython:

Теперь откроем снова оболочку IPython, чтобы взглянуть на содержимое переменной PATH:

Мы можем удалить сохраняемые изменения значения переменной PATH:

и проверить получившееся значение переменной PATH:

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

Хотя была дана команда удалить сохраняемые изменения для переменной PATH, они по-прежнему остаются на месте. Это означает лишь то, что оболочка IPython удалила указание на необходимость сохранения этих изменений. Обратите внимание, что процесс, запущенный с определенными значениями в переменной окружения, будет сохранять их, если не изменить их некоторым способом. При следующем запуске оболочки IPython окружение изменится:

Как и следовало ожидать, переменная PATH вернулась к значению, которое предшествовало тому моменту, как мы внесли в нее изменения.

Еще одна полезная особенность в профиле sh - это специальная функция mglob. Функция mglob имеет простой синтаксис для наиболее распространенных вариантов использования. Например, чтобы отыскать все файлы с расширением .ру в проекте Django, можно было бы воспользоваться следующей командой:

Директива rec предписывает выполнить рекурсивный поиск по заданному вслед за ней шаблону. В данном случае шаблоном служит *ру. Чтобы отобразить список всех каталогов в корневом каталоге проекта Django, можно было бы воспользоваться следующей командой:

Функция mglob возвращает объект списка, поэтому все, что в языке Python можно сделать со списком, можно сделать и с полученным списком каталогов.

Это была демонстрация лишь некоторых особенностей поведения профиля sh. Существуют другие особенности и параметры этого профиля, которые мы не рассматривали.

Комментарии (0)

RSS feed Comments

Написать комментарий

smaller | bigger

busy
 

Регистрация




Top