Unix2019a/Командная оболочка

Материал из iRunner Wiki

Командная оболочка UNIX (англ. Unix shell, часто просто «шелл») — командный интерпретатор, используемый в операционных системах семейства Unix, в котором пользователь может либо давать команды операционной системе по отдельности, либо запускать скрипты, состоящие из списка команд.

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

Виды

В первую очередь, под shell понимаются POSIX-совместимые оболочки, восходящие к Bourne shell (шелл Борна).

Условно оболочки можно разделить их на четыре группы:

  • Клоны Bourne shell (bash, zsh)
  • C shell (csh, tcsh)
  • Базирующиеся на популярных языках программирования (psh, ipython, scsh)
  • Экзотические, специфические и все остальные

История

Thompson shell

Первая оболочка Unix — Thompson shell, написанная Кеном Томпсоном в Bell Labs (1971–1975). По современным представлениям выглядит неразвитой, но уже поддерживала перенаправления ввода/вывода, метасимволы (wildcards) для имён файлов, простые управляющие выражения с if, goto (но они были сделаны через отдельные программы). Эта оболочка проектировалась под влиянием оболочки Multics, которая, в свою очередь, делалась на базе программы RUNCOM. Это название можно встретить на современных системах в суффиксе "rc" файлов конфигурации (например, .vimrc и .bashrc).

Так, у Томпсона перенаправление выглядело следующим образом:

command1 >command2>

Такой синтаксис был затем заменён на привычный

command1 | command2

Затем появилась оболочка PWB shell (другое название — Mashey shell) (1975–1977). Там появились переменные (предшественники переменных окружения), доступ к ним через $, запуск скриптов, доработаны операторы if/then/else/endif, switch/breaksw/endsw и while/end/break/continue. Но она не стала особо популярной.

Позже появились оболочки Bourne shell и C shell, которые оказали наибольшее влияние на развитие Unix-оболочек.

Bourne shell

Stephen R. Bourne

Оболочка Bourne shell (часто называют sh по имени исполняемого файла) разработана с нуля Стивеном Борном (Stephen R. Bourne). Внедрена в ОС Unix в 1979 г (в седьмую версию ОС). Большая часть операторов была заимствована им из языка ALGOL 68. Например, наследие этого языка: перевёрнутое ключевое слово используется для завершения блока (iffi, caseesac). Приглашение командной строки отображается в виде доллара $.

Оболочка Борна выполняла две основные задачи:

  • служила интерпретатором команд, позволяя выполнять команды в интерактивном режиме;
  • позволяла создавать сценарии (скрипты), которые можно было неоднократно вызывать с помощью оболочки.

Новая командная оболочка Bourne again shell (bash) разработана в 1987 году Брайаном Фоксом (Brian Fox) в рамках Free Software Foundation (Столлман). Фамилия Bourne (Борн) перекликается с английским словом born, означающим «родившийся», отсюда: рождённая-вновь-командная оболочка.

Подавляющее большинство важных скриптов командного процессора Борна могут выполняться без изменения в bash.

Командная оболочка Z shell (исполняемый файл zsh) — свободная современная sh-совместимая оболочка. Имеет ряд преимуществ перед bash, касающихся в основном работы в интерактивном режиме. Первая версия zsh была написана Паулем Фалстадом (Paul Falstad) в 1990 году.

C shell

Оболочка csh написана Биллом Джоем (Bill Joy) в университете Беркли в рамках проекта по реализации BSD Unix (1979). Билл также известен как автор текстового редактора vi.

За основу для скриптового языка csh был взят, как понятно из названия, язык C. Т.к. на тот момент, в 1978 г., это был наиболее популярный язык программирования среди разработчиков и пользователей BSD UNIX.

В настоящий момент более популярна свободная реализация csh — tcsh, или TENEX C Shell. Именно в tcsh когда-то впервые появилось автодополнение. Является оболочкой по умолчанию в FreeBSD.

Синтаксис csh на первый взгляд может показаться соблазнительным, потому что похож на C, но в общем использовать эту оболочку для написания скриптов не рекомендуется. Не хватает возможностей по работе с потоками (stdout и stderr) и поддержки функций. В самом интерпретаторе csh используется плохой примитивный парсер (в связи с тем, что в 70-е не была развита наука о компиляторах), из-за чего некоторые на вид корректные скрипты не работают так, как ожидается. Сообщения об ошибках парсинга очень неинформативные.

Кроме недостатка функциональности, можно заметить, что количество книг, справочных ресурсов, вопросов на Stackoverflow и пр. для tcsh гораздо меньше, чем для bash.

Современное состояние

Традиционно в Unix-системах шелл Борна называется sh и, согласно FHS, лежит в /bin/sh. На настоящих системах это часто символическая или жёсткая ссылка на один из альтернативных шеллов:

  • ash (Almquist shell, оболочка Альмквиста);
  • bash (Bourne-again shell, «ещё-одна-командная-оболочка-Борна»);
  • dash (Debian Almquist shell);
  • ksh (Korn shell);
  • zsh (Z shell, современная, имеет ряд преимуществ перед bash касающихся в основном работы в интерактивном режиме);
  • BusyBox — современная микро-версия, предназначенные для встраиваемых систем;
  • ...

Стандарт POSIX специфицирует стандартную оболочку как строгое подмножество Korn shell, расширенной версии оригинальной Bourne shell.

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

Оболочки в Ubuntu

Начиная с версии Ubuntu 6.10 (октябрь 2006 г.), ссылка /bin/sh изменена с bash на dash. Это привело к неработоспособности многочисленных скриптов.

bash остаётся оболочкой для входа в систему по умолчанию.

Главная причина — эффективность. Оболочка dash более легковесна, при загрузке ОС выполняется большое количество скриптов, в которых возможности bash избыточны.

sobols@sobols-VirtualBox:~$ ls /bin/*sh -l
-rwxr-xr-x 1 root root 1017016 Крс 24  2014 /bin/bash
-rwxr-xr-x 1 root root  121272 Лют 19  2014 /bin/dash
lrwxrwxrwx 1 root root       4 Врс 19  2014 /bin/rbash -> bash
lrwxrwxrwx 1 root root       9 Врс 14 09:36 /bin/sh -> /bin/dash
lrwxrwxrwx 1 root root       7 Врс 19  2014 /bin/static-sh -> busybox

Узнать текущую оболочку

echo $0
echo $SHELL

Терминалы

Ядра UNIX-систем имеют общее понятие терминалов. Терминал предоставляет возможность приложениям отображать выходные данные и принимать входные данные через терминальное устройство. Процесс может иметь управляющий терминал - для приложения с текстовым режимом, так он взаимодействует с пользователем.

Терминалы могут быть:

  • аппаратными терминалами («tty», от «телетайп»),
  • псевдотерминалами («pty»).

Аппаратные терминалы подключаются через некоторый интерфейс, такой как последовательный порт (ttyS0, ...) или USB (ttyUSB0, ...), или через экран ПК и клавиатуру (tty1, ...). Псевдотерминалы предоставляются терминальным эмулятором, который является приложением. Файлы в каталоге /dev/pts являются псевдотерминалами.

Некоторые типы псевдотерминалов:

  • Приложения GUI, такие как xterm, gnome-terminal, konsole, ... преобразуют клавиатуру и события мыши в текстовый ввод и вывод изображения графически некоторым шрифтом.
  • Мультиплексорные приложения, такие как screen и tmux, передают ввод и вывод на другой терминал, чтобы отделить приложения от фактического терминала.
  • Удаленные приложения оболочки, такие как sshd, telnetd, rlogind, ... передают ввод и вывод между удалённым терминалом на клиенте и pty на сервере.

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

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

Чтобы поэкспериментировать, запустите команду tty в терминале, чтобы узнать, какое терминальное устройство используется. Скажем, это /dev/pts/42. В шелле в другом терминале запустите echo

echo hello> /dev/pts/42

Приветствие hello будет отображаться на другом терминале. Теперь запустите

cat /dev/pts/42

и введите в другой терминал. Чтобы убить эту команду, нажмите Ctrl+C.

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

При нажатии клавиш Ctrl+Alt+F1, Ctrl+Alt+F2, из графической оболочки Linux-дистрибутива можно попасть в текстовый режим в терминалы tty1, tty2, ... Для возврата обратно в графический режим обычно можно нажать Ctrl+Alt+F7.

Запуск программ

Различают:

  • бинарные исполняемые файлы (в формате ELF и пр.);
  • текстовые программы (скрипты) на интерпретируемых языках.

И те, и те файлы в UNIX-системах имеют выставленные биты права на выполнение. Право на выполнение (x) означает, что вы можете загрузить файл в память и попытаться запустить его на выполнение как исполняемую программу. Загрузчик по первым байтам понимает, как запускать этот исполняемый файл.

Шебанг (shebang)

Последовательность из двух символов: решётки и восклицательного знака (#!) в начале файла скрипта.

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

#!interpreter [optional-arg]

interpreter должен быть абсолютным путём.

Пример: в файле some/path/to/foo записано

#!/bin/sh -x

и он запускается как

some/path/to/foo bar baz

Это то же самое, что запустить

/bin/sh -x some/path/to/foo bar baz

Вопрос: что будет, если запустить

#!/bin/cat
Hello world!

Ответ: напечатаются обе строки.

Переменная окружения PATH

Переменная окружения PATH представляет собой набор каталогов, в которых расположены исполняемые файлы. В основном, каждый выполняемый процесс или сеанс пользователя имеет собственную переменную PATH.

На POSIX и Unix-подобных операционных системах переменная PATH задана как одно или несколько имён каталогов, разделённых двоеточиями (:).

echo $PATH

Согласно стандарту POSIX, использовать каталоги с двоеточием в имени не получится.

Since <colon> is a separator in this context, directory names that might be used in PATH should not include a <colon> character.

В основном в переменную PATH входят каталоги /bin, /usr/bin и /usr/local/bin.

Текущий каталог (.) обычно в PATH не входит из соображений безопасности, чтобы избежать случайного исполнения скриптов из текущего каталога. Запуск такой программы требует написания (./) перед названием.

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

/usr/bin/env

Для переносимости, чтобы не указывать полный путь к интерпретатору, в шебанг прописывают программу /usr/bin/env. Например,

/usr/bin/env python

запустит первый python, который будет найден в PATH.

Пусть есть следующий скрипт на Python:

#!/usr/bin/env python
 
import sys
print sys.executable

Запустим его:

sobols@sobols-VirtualBox:~/unix/path$ ./main.py 
/usr/bin/python

sobols@sobols-VirtualBox:~/unix/path$ virtualenv venv
Running virtualenv with interpreter /usr/bin/python2
New python executable in /home/sobols/unix/path/venv/bin/python2
Also creating executable in /home/sobols/unix/path/venv/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.

sobols@sobols-VirtualBox:~/unix/path$ source ./venv/bin/activate

(venv) sobols@sobols-VirtualBox:~/unix/path$ ./main.py 
/home/sobols/unix/path/venv/bin/python

Не используйте /bin/bash

#!/bin/bash в качестве shebang использовать не стоит, т. к. место расположения bash не специфицируется FHS (в принципе, он может лежать в /usr/bin/bash, например – так обстоят дела по крайней мере в некоторых версиях FreeBSD).

Вместо

#!/bin/bash

следует использовать

#!/usr/bin/env bash

Если вы ничего bash-специфичного не используете, рекомендуется использовать

#!/bin/sh

(на некоторых системах sh ссылается на bash, но на других это могут быть более простые и быстрые оболочки, а bash в принципе может быть не установлен).

Создание сценариев командной оболочки (шелл-скриптов)

Сценарий представляет собой обычный текстовый файл, редактируемый в текстовом редакторе. Можно выбрать по вкусу

  • nano / mcedit (mc F4) / evim
  • gedit
  • Sublime Text
  • ...

Расширение файла значения не имеет. Часто используется .sh.

chmod +x script.sh