Командный язык shell. Основы программирования в командной оболочке shell

    Операционные системы семейства Linux, как впрочем, и любые другие ОС, предполагают наличие интерфейса взаимодействия между компонентами компьютерной системы и конечным пользователем, т. е. наличие программного уровня, который обеспечивает ввод команд и параметров для получения желаемых результатов. Такой программный уровень получил название "оболочка" или, на английском языке - shell .

Что такое оболочка?

Командная оболочка (shell ) обеспечивает взаимотействие между пользователем и средой операционной системы Linux. Она является специализированным программным продуктом, который обеспечивает выполнение команд и получения результатов их выполнения, или, если совсем уж упрощенно, оболочка - это программа, которая предназначена для обеспечения выполнения других программ по желанию пользователя. Примером оболочки может быть, например, интерпретатор команд command.com операционной системы MS DOS, или оболочка bash операционных систем Unix / Linux.

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

Интерпретация командной строки.

Доступ к командам и результатам их выполнения.

Поддержка переменных, специальных символов и зарезервированных слов.

Обработка файлов, операций стандартного ввода и вывода.

Реализация специального языка программирования оболочки.

    Для операционных систем семейства Unix / Linux возможно использование нескольких различных оболочек, отличающихся свойствами и методами взаимодействия с системой. Наиболее распространенными оболочками являются

sh - оболочка Bourne , классическая оболочка для ОС Unix

bash оболочка Bourne Again (GNU Bourne-Again SHell). Пожалуй, наиболее распространенная на данный момент, оболочка в среде ОС семейства Linux.

ksh - оболочка Korn , разработанная в качестве развития оболочки Bourne с историей командной строки и возможностью редактирования команд.

csh - оболочка C , использующая синтаксис популярного языка программирования C

tcsh - версия оболочки C с интерактивным редактированием командной строки.

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

    В процессе загрузки операционных систем семейства Linux, после загрузки ядра системы выполняется переход в интерактивный режим – режим взаимодействия пользователя и операционной системы. В ОС Linux, первым запускаемым в ходе загрузки процессом, является программа инициализации init , которая считывает содержимое конфигурационного файла /etc/inittab , определяет перечень и характеристики терминалов, имеющихся в системе, и вызывает программу интерактивного входа getty , отображающую приглашение для ввода имени пользователя. После ввода имени пользователя и пароля, программа getty вызывает программу login , которая проверяет достоверность учетной записи, выполняет переход в домашний каталог пользователя и передает управление программе начального запуска сеанса, в качестве которой обычно используется программа оболочки пользователя, конкретная разновидность которой определяется содержимым файла /etc/passwd для данной учетной записи. Например:

user1:x:508:511::/home/user1:/bin/sh
interbase:x:510:511::/home/interbase:/bin/csh
apb:x:511:513:apb:/home/apb:/bin/bash

Как видно из содержимого файла /etc/passwd , для пользователя user1 будет запущена оболочка sh (оболочка Bourne), для пользователя interbase - оболочка csh (оболочка C) и для пользователя apb - оболочка bash (Bourne Again). После старта оболочки, на экран выводится приглашение к вводу команд (обычно в виде знака доллара $ , если работа выполняется в контексте учетной записи обычного пользователя, или фунта # , если оболочка используется под учетной записью привилегированного пользователя (root ).

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

Посредством команды exit выполненной пользователем

При получении процессом оболочки сигнала kill , отправленного ядром, например при перезагрузке системы.

Интерпретация командной строки.

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

ls -l file01 file02

Содержит команду ls , опцию -l и два имени файлов file01 file02 .

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

Ls -l -d
ls -ld

Команды, являющиеся частью оболочки, называются встроенными . К таким командам относятся, например, cd, if, case и т. п. Естественно, встроенные команды могут отличаться для различных вариантов оболочек. Кроме встроенных команд, возможно использование программных модулей, представляющих собой отдельные исполняемые файлы, или файлов скриптов или сценариев - обычных текстовых файлов, содержащих последовательно выполняемые строки с командами оболочки. Некоторые скрипты (сценарии) могут выполняться процессами Linux, как например, планировщиком задач cron . Планировщик задач, как правило, предназначен для автоматического выполнения задач администрирования системы по расписанию. Задачи cron представляют собой команды или скрипты и выполняются автоматически, без какого либо вмешательства человека и могут выполняться в контексте разных учетных записей пользователей. В случае, когда задача планировщика предполагает выполнение какого-либо скрипта, возникает проблема выбора оболочки, которая должна быть запущена в качестве дочернего процесса cron для обработки команд из файла скрипта - ведь оболочка может быть любой, а синтаксис скрипта, как правило, предполагает использование конкретной оболочки, под которую он написан. Для устранения данной проблемы, в ОС семейства Linux принято в первой строке скрипта указывать разновидность оболочки, необходимой для его выполнения, в виде:

#!/bin/bash - для оболочки bash

#!/bin/sh - для оболочки sh

Знак # является признаком комментария и следующие за ним символы не интерпретируются в качестве команды. Такой прием позволяет явно указать, какая оболочка должна быть использована для обработки последующего содержимого файла. Если же скрипт не содержит запись, явно определяющую требуемую оболочку, то будут использованы настройки из учетной записи, в контексте которой выполняется данный скрипт. В этом случае, возможна ситуация, когда скрипт, написанный для оболочки, например, tch будет передан для выполнения в оболочку bash , что приведет к невозможности его выполнения.

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

/etc/profile - устанавливает переменные только для командных оболочек. Может запускать любые скрипты в оболочках, совместимых с Bourne shell.

/etc/bash.bashrc - устанавливает переменные только для интерактивных оболочек. Он также запускает bash-скрипты.

/etc/environment - используется модулем PAM-env. В этом файле можно указывать только пары имя=значение .

Каждый из этих файлов имеет свои особенности применения, поэтому следует внимательно выбирать тот, который подходит для ваших целей. Например, если нужно добавить пользовательский каталог ~/bin в переменную PATH для всех пользователей, поместите следующий код в один из системных файлов инициализации окружения (/etc/profile или /etc/bash.bashrc):

# Если идентификатор ID пользователя более или равно 1000, и существует каталог ~/bin, и он

#не был ранее добавлен в переменную PATH,

# выполнить экспорт ~/bin в переменную $PATH.

If [[ $UID -ge 1000 && -d $HOME/bin && -z $(echo $PATH | grep -o $HOME/bin)

Export PATH=$HOME/bin:${PATH}

Как правило, в операционных системах Linux, идентификатор пользователя менее 1000 или менее 500 используется для служебных учетных записей. В данном примере, переменная окружения будет установлена для всех локальных пользователей системы с идентификатором 1000 или более.

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

- ~/.bash_profile , ~/.bash_login и т.п. - файлы инициализации командной оболочки из домашнего каталога пользователя.

- ~/.profile - файл инициализации профиля пользователя. Используется многими оболочками для определения переменных среды.

~/.pam_environment - пользовательский аналог файла /etc/environment, который используется модулем PAM-env.

Например, чтобы добавить каталог пользователя ~/bin в пути поиска исполняемых файлов, заданных переменной PATH , можно например, в файл ~/.profile поместить строку:

export PATH="${PATH}:/home/пользователь/bin"

Чтобы установить переменные окружения для графических приложений, используется содержимое файлов настройки графической среды пользователей ~/.xinitrc

Гораздо чаще значения переменных окружения задаются для текущего сеанса пользователя. Например, для добавления пользовательского каталога ~/bin в пути поиска исполняемых файлов:

export PATH=~/bin:$PATH

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

Для просмотра значения переменной можно использовать команду echo $переменная , например:

echo $PATH

В настоящее время, самой распространенной оболочкой, как уже упоминалось выше, является bash . Вызвано это, в первую очередь тем, что оболочка bash является sh - совместимой командной оболочкой, в которую добавлены полезные возможности из оболочек Korn shell (ksh ) и C shell (csh ). Оболочка bash может без какой-либо модификации выполнять большинство скриптов, написанных под язык программирования оболочки sh и в максимальной степени пытается приблизиться к стандарту POSIX , что привело к появлению множества улучшений, причем как для программирования, так и использования в интерактивном режиме. В современной реализации bash имеется режим редактирования командной строки, неограниченный размер истории команд, средства управление заданиями, возможность использования псевдонимов, обширный перечень встроенных команд, функции командной оболочки и т.п. В целом, bash в наибольшей степени соответствует потребностям среднестатистического пользователя, что и сделало ее наиболее используемой в среде Linux.

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

Любой универсальной ОС приходится много возиться с пользовательскими и своими собственными задачами. Лишь небольшая часть этой деятельности может быть запрограммирована раз и навсегда в ядре. Большая часть логики управления задачами и самой системой должна быть доступна администратору в виде проекта, иначе он просто не сможет ни понять происходящее в системе, ни тем более изменять ее. Стоит повнимательнее взглянуть на инструмент, используемый в UNIX для задания алгоритма работы многих частей системы, - на командный интерпретатор , shell . Оказывается, shell отлично себя показывает не только в диалоге с пользователем, но и как исполнитель сценариев , и как средство организации взаимодействия между задачами в системе.

Начнем с того, что shell - полноценный язык программирования , причем, как многие интерпретаторы, довольно высокого уровня. Если задача - разовая (нет требований по быстродействию, совместимости и переносимости) и достаточно абстрактная (нет привязки к конкретной сложной структуре данных), ее скорее всего можно решить, написав командный сценарий - программу на shell .

С другой стороны, одной алгоритмической полнотой при решении задач в системе ограничиваться нельзя. Скажем, машина Тьюринга [ 9 ] чрезвычайно проста и алгоритмически полна, однако мало кому придет в голову организовывать на основе ее модели диалог с пользователем или управление самой ОС. Здесь следует вспомнить, что shell - еще и исполнитель команд: он запросто общается с UNIX и утилитами. Значит, дополнив его механизмом управляемого взаимодействия команд с системой и друг с другом, мы получим неплохой интегратор (или оболочку - что, собственно, и есть перевод слова shell ).

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

Сценарий

Прежде чем рассмотреть возможности shell под двумя углами зрения, разрешим вот какое затруднение. Допустим, мы написали программу на языке какого-нибудь интерпретатора, например /bin/sh , и записали ее в некий файл , например /home/george/myscript (если /home/george - текущий каталог , можно использовать более короткий путь : myscript ). Как теперь выполнить этот сценарий ? Из man sh мы знаем, что для этого можно запустить командный интерпретатор с параметром - именем файла:

$ cat myscript echo "Hello, George!" $ /bin/sh myscript Hello, George!

Нельзя ли обойтись без имени программы, которая интерпретирует сценарий ? Вообще говоря, нет: в UNIX немало различных интерпретаторов с разнообразным синтаксисом, например обработчик текстов awk , потоковый текстовый редактор sed , универсальные языки программирования python и perl и много чего еще. Во всех этих языках есть возможность вставлять в текст сценария строчные комментарии, которые начинаются с символа "#" и заканчиваются в конце строки. Поэтому, если сценарий начинается с символов " # !", любой из этих интерпретаторов проигнорирует всю первую строку как комментарий. Система же, увидев " # !" в начале файла, понимает, что это сценарий . С третьего символа и до конца строки она читает имя программы , которой отдает этот файл на выполнение. Значит, если первой строкой в /home/george/myscript будет #!/bin/sh , его смело можно делать исполняемым (установить бит использования) и запускать:

$ chmod +x myscript $ cat myscript #!/bin/sh echo "Hello, $1!" $ ./myscript George Hello, George!

Строго говоря, после " # !" может стоять что угодно, например имя написанной нами программы с некоторыми обязательными параметрами; UNIX ее запустит и передаст ей в качестве параметров командной строки обязательные параметры (если они есть), затем имя сценария и все, что идет следом (в нашем примере George ). Если же после " # !" будет стоять несуществующий файл , система выдаст сообщение об ошибке :

$ cat myscript #!/bad/sh echo "Hello, $1!" $ ./myscript ./myscript: not found

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

Гнезда shell`ов

И еще одно немаловажное замечание. Сначала в UNIX был только один командный интерпретатор , написанный Стивеном Борном (Stephen Bourne), и назывался он просто "оболочка" (т. е. shell , а имя утилиты, для краткости, sh). Это была очень простая маленькая программа , она отлично работала именно как системный интегратор , но во всех остальных ипостасях была довольно слабой. И вот создателям 3BSD пришло в голову, что нужен совершенно новый командный интерпретатор , более удобный при работе в командной строке, с новыми возможностями программирования и с новым синтаксисом, приближенным к языку Си , который и так знаком любому UNIX -программисту. Получившуюся оболочку назвали C shell (за синтаксис команд; имя утилиты - csh ), она была намного мощнее старой, там была работа с историей, достраивание имен файлов, управление заданиями ; появились массивы и много чего еще.

Что такое shell и зачем он нужен

Командная оболочка в любых unix-подобных системах, к которым относится и GNU/Linux, является обычной программой, запускаемой как в текстовой консоли (которая используется всё реже), так и в графической среде – в окне эмулятора терминала, доступного в любой Linux-системе.

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

Почти во всех дистрибутивах Linux для пользователей по умолчанию назначается командная оболочка bash (Bourne Again SHell – ещё одна командная оболочка Бурна; Стив Бурн – автор первой командной оболочки в Unix – sh). Фактически она стала неофициальным стандартом, и усовершенствование ее функциональных возможностей продолжается непрерывно. Существуют и другие командные оболочки – tcsh (версия C-shell), ksh (Korn Shell), zsh и т.д. – у каждой есть свои достоинства и недостатки, а также свои группы поклонников. Тем не менее, bash более привычна широким массам пользователей с различными уровнями подготовки, потому я и остановил свой выбор на ней. Стоит также отметить, что какими бы возможностями ни обладали различные оболочки, все они совместимы со своим идеологическим прародителем – Bourn Shell (sh). Иными словами, скрипт, написанный для sh, будет корректно работать в любой современной оболочке (обратно, вообще говоря, неверно).

Преимущества командной строки

Может возникнуть вопрос: зачем возиться с командной строкой, если существуют удобные и красивые графические интерфейсы? Тому есть множество причин. Во-первых, далеко не все операции удобнее и быстрее выполнять с помощью графического интерфейса. Во-вторых, каждая программа следует основополагающему принципу Unix-систем: делать чётко определённую работу и делать её хорошо. Иными словами, вы всегда понимаете, что происходит при запуске той или иной утилиты (если что-то не вполне понятно, то следует обратиться к man-руководству). В-третьих, осваивая команды, пробуя их сочетания и комбинации их параметров, пользователь изучает систему, приобретая ценный практический опыт. Вы получаете доступ к таким эффективным инструментам, как конвейеры, позволяющие организовать цепочку команд для обработки данных, средства перенаправления ввода/вывода, а кроме того, можете программировать непосредственно в командной оболочке. Пожалуй, на программировании стоит остановиться подробнее, тем более что многие системные сценарии в Linux (например, скрипты запуска системных сервисов) написаны для shell.

Командная оболочка в качестве языка программирования

Итак, командную оболочку можно рассматривать как язык программирования и как программную среду выполнения одновременно. Разумеется, этот язык не компилируемый, а интерпретируемый. Он допускает использование переменных: системных или собственных. Последовательность выполнения команд программы изменяется с помощью конструкций проверки условия и выбора соответствующего варианта: if-then-else и case. Циклы while, until и for позволяют автоматизировать многократно повторяющиеся действия. Имеется возможность объединять группы команд в логические блоки. Вы можете даже писать настоящие функции с передачей в них параметров. Таким образом, налицо все признаки и характеристики полноценного языка программирования. Попробуем извлечь из этого двойную пользу – наряду с изучением основ программирования автоматизируем свою повседневную работу.

Hello, World! Простая система резервного копирования

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

#!/bin/bash # # Резервное копирование каталогов и файлов из домашнего каталога # Этот командный скрипт можно автоматически запускать при помощи cron # cd $HOME if [ ! -d archives ] then mkdir archives fi cur_date=`date +%Y%m%d%H%M` if [ $# -eq 0 ] ; then tar czf archive${cur_date}.tar.gz projects bin else tar czf archive${cur_date}.tar.gz $* fi if [ $? = 0 ] ; then mv archive${cur_date}.tar.gz $HOME/archives echo "$cur_date – Резервное копирование успешно завершено." else echo "$cur_date – ОШИБКА во время резервного копирования." fi

Любой командный сценарий (script – скрипт, так называются программы командной оболочки) начинается со строки идентификатора, в которой явно задаётся интерпретатор команд с указанием полного пути к нему. Полный путь – последовательное перечисление всех каталогов, начиная с корневого, в которые надо войти, чтобы добраться до целевого файла, и, разумеется, имя этого файла. Запись полного пути чрезвычайно важна для однозначной идентификации каждого файла в иерархии файловой системы.

Далее следуют четыре строки комментариев. Как только командная оболочка встречает символ "#", она считает все последующие символы комментариями и полностью игнорирует их до конца текущей строки. Поэтому комментарий можно начать не с самого начала строки, а сопроводить им какую-либо команду.

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

Наконец-то мы добрались до первой «настоящей» команды. Она позволяет сменить каталог (Change Directory), т.е. перейти из текущего каталога в другой, переданный команде как аргумент. В большинстве случаев целевой каталог задаётся в явной форме, например, cd /tmp или cd projects, но в нашем случае используется предопределённая системная переменная HOME – в ней содержится полный путь к домашнему каталогу текущего пользователя, от имени которого выполняется командный сценарий. Тем самым мы избавляемся от необходимости вносить изменения в код всякий раз при смене пользователя, потому что команда возвращает любого в его личный каталог. Знак доллара "$" перед именем переменной означает, что необходимо извлечь значение, содержащееся в этой переменной, и подставить его в командную строку вместо её имени. Особо следует отметить, что в командном языке оболочки регистров букв имеют важное значение, т.е. HOME, Home и home – это три различные переменные. По соглашению, буквами верхнего регистра обозначаются имена системных переменных: HOME, PATH, EDITOR и т.д. Это соглашение не запрещает пользователям создавать свои переменные с именами из заглавных букв, но зачем усложнять себе жизнь, нарушая общепринятые нормы и правила? Не рекомендуется также изменять значения системных переменных без крайней необходимости. В общем, соблюдаем простое правило: системные переменные используем только для чтения, а если потребовалась собственная, то её имя записываем буквами нижнего регистра.

Нашу первую команду можно было бы записать более кратко:

cd ~

Здесь символ "~" также означает домашний каталог текущего пользователя. Ветераны командной строки выражаются ещё лаконичнее:

cd

Смысл в том, что когда для команды cd не задан никакой аргумент, она выполняет переход в домашний каталог.

На очереди классическая программная конструкция проверки условия и принятия соответствующего решения. Общая схема такова:

if <условие> then <одна или несколько команд> fi

Последнее слово конструкции (if в обратном порядке) выполняет роль закрывающей скобки, т.е. границы списка команд, выполняемых при истинности условия. Присутствие fi обязательно, даже если в списке лишь одна команда.

Для проверки условия, как правило, применяется команда test или её альтернативная форма записи в квадратных скобках. Иначе говоря, записи

if [ ! -d archives ] if test ! -d archives

абсолютно равнозначны. Я предпочитаю квадратные скобки, поскольку они более наглядно определяют границы проверяемого условия. И правая, и левая скобка должны быть обязательно отделены от условия пробелами.

Критерии проверки условия определяются разнообразными флагами. Команда test распознаёт очень большой их список. В нашем примере использован флаг -d, позволяющий проверить, соответствует ли заданное после флага имя реально существующему каталогу (directory). Наиболее часто при работе с файлами применяются следующие флаги:

F – существует ли обычный файл с заданным именем;

R – установлено ли для заданного файла право на чтение из него;

W – установлено ли для заданного файла право на запись в него;

X – установлено ли для заданного файла право на его выполнение;

S – имеет ли заданный файл ненулевой размер.

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

if [ ! -d archives ] Если не существует каталог archives (в текущем каталоге), then то начать выполнение блока команд: mkdir archives создать каталог archives (в текущем каталоге) fi завершить выполнение блока команд.

Как видите, всё оказалось не таким уж и сложным. Немного практики, и вы без труда сможете читать и самостоятельно создавать подобные конструкции. Команда создания каталога настолько очевидна, что дополнительных разъяснений не требуется.

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

ten=10 string="Это строка текста"

Но в нашем примере применяется небольшая хитрость. Обратите внимание, что после знака равенства – символа присваивания – записана команда в обратных кавычках. Такая форма записи позволяет присвоить переменной не саму строку, а результат её выполнения. Здесь это вывод команды date, которая возвращает текущую дату и время в формате, определяемом списком параметров:

%Y – текущий год в полной форме, т.е. из четырёх цифр (например, 2009);

%m – номер текущего месяца (например, 09 – для сентября);

%d – номер текущего дня;

%H – текущий час в 24-часовом формате;

%M – текущая минута.

Таким образом, если выполнить команду

cur_date=`date +%Y%m%d%H%M`

десятого сентября 2009 года в 22:45, то переменной cur_date будет присвоено строковое значение "200909102245". Цель этого ухищрения – сформировать уникальное, не повторяющееся имя архивного файла. Если вы намерены запустить несколько экземпляров программы в течение одной минуты, то можете улучшить уникальность имён, добавляя ещё и текущие секунды. Как? Изучите руководство утилиты date (man date) – в этом нет ничего сложного.

Прежде чем приступить к созданию файла архива, необходимо определить, какие именно каталоги мы будем сохранять в нём. Для большей гибкости можно задать набор каталогов, архивируемых по умолчанию, но предусмотреть возможность замены этого набора списком каталогов, передаваемым как аргумент в наш командный сценарий. Для этого используются специальные переменные командной оболочки: $# – число переданных в сценарий параметров и $* – все переданные параметры, записанные в формате одной строки.

if [ $# -eq 0 ] ; then

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

tar czf archive${cur_date}.tar.gz projects bin

Команда создания архивного файла и сжатия этого файла. Сама утилита tar не выполняет сжатие, а только лишь собирает все заданные файлы и каталоги в единый tar-файл. Для этого предназначен первый флаг - c (create – создать). Сжатие выполняет внешняя программа – здесь это gzip, вызываемый вторым флагом - z. Если в вашей системе установлена более эффективная программа сжатия bzip2, то вы можете воспользоваться ею, изменив команду следующим образом:

tar cjf archive${cur_date}.tar.bz2 projects bin

Третий флаг f сообщает о том, что далее следует имя архивного файла, поэтому всегда является замыкающим в перечне флагов. Обратите внимание на то, что при подстановке имя переменной заключено в фигурные скобки. Это сделано, чтобы явно выделить переменную в окружающей её строке, тем самым устраняя многие потенциальные проблемы. Расширения архивному файлу не присваиваются автоматически, вы сами дописываете всё необходимое. В качестве каталогов, архивируемых по умолчанию, я указал projects и bin, но вы можете записать здесь имена своих наиболее ценных каталогов.

Ключевое слово else открывает альтернативную ветвь выполнения. Команды этого блока начинают работать, если проверка условия даёт результат «ложь» (в нашем примере: «число переданных параметров ненулевое», т.е. пользователь задал имена каталогов). В этом случае команда будет выглядеть так:

tar czf archive${cur_date}.tar.gz $*

Здесь каталоги по умолчанию заменены строкой имён каталогов, принятой извне. Имеется возможность принимать и обрабатывать каждый внешний параметр по отдельности, но нам удобнее передать строку целиком.

В конце программы выполняется ещё одна проверка. В unix-средах все команды возвращают код статуса завершения своей работы. Если команда отработала успешно, то она возвращает код 0, в противном случае код завершения будет ненулевым. Чтобы проверить успешность выполнения предыдущей команды архивации, воспользуемся ещё одной специальной переменной $?, в которой всегда содержится значение кода завершения самой последней команды. Если в переменной $? содержится 0, т.е. файл резервной копии был успешно создан, то мы перемещаем его в каталог архивов:

mv archive${cur_date}.tar.gz $HOME/archives

и выдаём соответствующее сообщение:

echo "$cur_date – Резервное копирование успешно завершено."

Если проверка показала, что код завершения операции архивирования не равен нулю, то выводится сообщение об ошибке:

echo "$cur_date – ОШИБКА во время резервного копирования."

На этом работа нашего командного сценария завершается.

Чтобы проверить работу нашей программы, необходимо сохранить описанный выше исходный код в файле, например, с именем bckp, а затем для удобства сделать его выполняемым:

chmod 750 bckp

и запустить:

./bckp

для создания резервной копии каталогов, заданных по умолчанию, и

./bckp docs progs works

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

Можно поместить файл bckp в один из каталогов, указанных в системной переменной PATH. Наиболее предпочтительными местами размещения являются /usr/local/bin или $HOME/bin, если таковые у вас имеются. После этого вы можете запускать bckp как системную команду.

Как автоматизировать операции резервного копирования «по расписанию»

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

crontab -e

Инструкции записываются в строго определённом формате (поля разделяются пробелами):

минуты часы день_месяца месяц день_недели команда

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

30 23 10,20,30 * * /usr/local/bin/bckp

Это означает, что сценарий резервного копирования (следует указать полный путь к этому файлу) будет выполняться в 23:30 10-го, 20-го и 30-го числа каждого месяца независимо от дня недели. (Звёздочки обозначают весь допустимый диапазон значений, в данном случае: каждый месяц – в 4-м поле, любой день недели – в 5-м поле)

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

0 5 * * 3,5 /usr/local/bin/bckp

Здесь резервные копии будут создаваться в 5:00 по средам и пятницам в каждом месяце (звёздочка в 4-м поле), независимо от числа (звёздочка в 3-м поле).

Обо всех тонкостях составления расписания можно прочитать в руководстве man 5 crontab.

Итоги и выводы

Рассмотренный в данной статье сценарий резервного копирования обладает скромными функциональными свойствами. Но не в этом состояла его главная задача, а в том, чтобы читатель понял, что можно делать в командной строке, и не только скопировал и выполнил предложенный командный файл, а заинтересовался расширением его функций, занялся исследованием необъятных возможностей, предоставляемых командными оболочками. И если кто-то, прочитав эту статью, попробует усовершенствовать приведённый здесь код, или напишет собственный вариант, или реализует свою независимую идею, то я сочту, что основная цель достигнута.

Ресурсы для скачивания

static.content.url=http://www.сайт/developerworks/js/artrating/

ArticleID=458335

ArticleTitle=Основы программирования в командной оболочке shell

Командные оболочки появились в самом начале развития Unix, они были необходимы, поскольку это был единственный способ взаимодействия с системой. За это время они прошли очень долгий путь развития и получили много новых функций. Не так просто оценить эволюцию командных оболочек Linux. Об этом можно писать очень долго и одной статьи точно не хватит. Мы постараемся только охватить самое основное не погружаясь очень глубоко. Давайте сначала рассмотрим что такое командная оболочка Linux и какие оболочки бывают.

Что такое командная оболочка Linux / Unix

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

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

Thompson Shell

Если верить истории и многим-интернет источникам, то самой первой оболочкой была Thompson Shell, написанная Кеном Томсоном в Bell Labs. Всего было 6 версий и распространялась она с 1971 по 1975 год. Поддерживались такие функции, как: перенаправление ввода / вывода и простые управляющие конструкции - if, goto. Эти функции поддерживают все современные командные оболочки в линукс.

PWB Shell

Оболочка PWB - это модификация оболочки Томсона разработанная Джоном Машеу. Она была написана для увеличения удобства Shell программирования. Появились такие интересные структуры, как if-then-else-endif, switch и циклы while.

Bourne Shell

Свой подъем Unix начал с оболочкой Борна. Она была написана Стефаном Борном в Bell Labs и использовалась как оболочка по умолчанию в Unix версии 7 от 1979 года. Здесь уже было реализовано большое количество возможностей доступных в современных оболочках - дополнение имен файлов, автодополнение команд, стандартные переменные окружения и встроенные управляющие структуры. Bourne Shell называлась sh и размещалась в файловой системе Unix по адресу /bin/sh.

Во многих системах программа оболочки Борна (sh) - это символическая или жесткая ссылка на одну из ее альтернатив:

  • Almquist shell (ash)
  • Bourne-Again shell (bash)
  • Korn shell (ksh)
  • Z shell (zsh)

Пример скрипта для Bourne Shell:

!/bin/sh
echo "Hello World 1!"
echo "Hello World 2!"

Almquist shell (ash)

Almquist shell, еще известная как A Shell. Это легкая оболочка Unix первоначально написанная Кеннетом Альмквистом. Она была разработана в конце 1980х. Это модификация оболочки Борна и она заменила оригинал в BSD Unix выпущенной в 1990 году. Сейчас ее можно использовать в таких дистрибутивах, как Debian и Ubuntu в виде версии ash под названием dash (Debian Almquist shell) Также эта оболочка популярна на встраиваемых Unix дистрибутивах.

Это быстрая, компактная и совместимая со спецификациями стандарта POSTIX оболочка Unux, и может быть именно поэтому она часто используется на встраиваемых устройствах. Но ash не поддерживает истории команд. Хотя в современных версиях эта функция уже добавлена.

Bourne-Again Shell (Bash)

Написанная Браеном Фоксом в рамках проекта GNU как бесплатная и свободная замена для оболочки Борна. Bash -наиболее популярная и широко используемая из всех оболочек. Все дистрибутивы Linux поставляются по умолчанию с этой оболочкой. Она расширяет набор функций Bourne Shell. В большинстве систем Unix / Linux эта оболочка может быть найдена в файловой системе по адресу /bin/bash. Она была выпущена в 1989 году.

Благодаря такой популярности она была портирована на Windows и распространяется вместе с набором компиляторов Cygwin и MinGW. Также Bash используется в Android, для доступа к ней можно использовать различные эмуляторы терминала.

Здесь поддерживается автодополнение, перенаправление ввода / вывода, дополнение команд, переменные и управляющие структуры для принятия решения (if-then-elese if) и циклы (loop).

Bash скрипты начинаются с такой строки:

Эта командная оболочка linux также поддерживает чтение команд из файла и перенаправление вывода в файл или другую команду.

Пример кода на Bash:

!/bin/sh
if [ $days -gt 365 ]
then
echo This is over a year.
fi

Korn shell (ksh)

Написана Девидом Кроном и основана на исходниках оболочки Борна. KornShell (ksh) это оболочка, разработанная в Bell Labs еще в 1980. Она имеет обратную совместимость с Bourne Shell, а также включает многие черты оболочки С.

Есть следующие версии и модификации:

  • Dtksh
  • MKS Korn shell

Пример скрипта:

!/bin/ksh
print Disk space usage
du -k
exit 0

Z shell (zsh)

Пол Фальстад написал первую версию командой оболочки zsh в 1990 году. Это командная оболочка Linux, которая может быть использована как интерактивная оболочка входа в систему, очень мощный интерпретатор команд. На самом деле Zsh это расширенная оболочка Борна с большим количеством улучшений, которая включает некоторые функции из Bash, KSH и Tcsh.

Имя Zsh происходит от имени Йельского профессора Чжун Шао (Zhong Shao) так как Пол был студентом Принстонского университета.

Поддерживаются такие интересные функции:

  • Автозавершение строк
  • Совместная история команд для всех сеансов оболочки
  • Улучшена работа с переменными и массивами
  • Редактирование нескольких строк в одном буфере
  • Коррекция орфографии и много другое.

C shell

Оболочка C также известна как Csh. Ее разработал Бил Джой когда был студентом Калифорнийского университета. Эта оболочка очень распространена в системах BSD Linux. Здесь есть много интересных особенностей, в том числе контрольные структуры и грамматические выражения. Эта оболочка также впервые представила большое количество интересных функций, таких как история и механизмы редактирования, псевдонимы, CDPATH, управление задачами и хеширование, перенаправление вывода, присоединение, замена переменных, выполнение в фоне и т д.

Как и другие виды командных оболочек Linux здесь поддерживаются файлы скриптов, перенаправление и управляющие структуры. Csh сейчас используется в виде tcsh во многих системах, например, MacOS X и Red Hat Linux. В Debian можно использовать оба варианта CSH и Tcsh.

Пример кода на C Shell:

!/bin/csh
if ($days > 365) then
echo This is over a year.
endif

Fish

Fish или Friendly Interactive Shell - это командная оболочка Linux нового поколения. Она разработана чтобы облегчить пользователю выполнение команд, есть подсветка синтаксиса, подсветка правильных адресов файлов, быстрый поиск по истории, веб-конфигуратор, а также особый синтаксис скриптов.

Это новая командная оболочка в Linux и ее синтаксис непохож ни на одну из современных командных оболочек, а скорее на язык программирования Python.

Пример создания функции на fish:

!/usr/bin/fish
funced su
function su
/bin/su --shell=/usr/bin/fish $argv
end
funcsave su

Более подробное сравнение командных оболочек в Linux вы можете посмотреть по ссылке .

Это все на сегодня. Надеюсь вам было интересно.

Наверняка почти все читатели Хабра знают оболочки sh и bash. Так же большинство из нас что-то слышали про zsh и tcsh. Однако на этом список существующих оболочек не заканчивается. Условно можно разделить их на три группы:

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

Целью написания статьи не был обзор или классификация всех существующих командных оболочек. Просто хочу рассказать о некоторых интересных продуктах в этой области, расширить кругозор читателя. Буду рад. если этим сподвигну кого-то к более детальному изучению темы или даже к тому, чтоб перейти на другой шел.
Сначала коротко о том, что же это такое. Командная оболочка или командный интерпретатор- это приложение предоставляющее пользователю интерфейс командной строки в которой тот либо вводит команды по отдельности, либо запускает скрипты состоящие из списка команд. Устно и в неофициальных текстах часто называется «шел», от английского shell - оболочка.

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

Bourne shell и его клоны

Bourne shell , исполняемый файл: sh . Командная оболочка названная в честь своего создателя Стивена Борна. Большая часть операторов была заимствована им из языка Алгол 68. Вышла в 7-м издании операционной системы UNIX, где была оболочкой по умолчанию. До сих пор подавляющее большинство Unix-подобных систем имеют /bin/sh - символическую или жесткую ссылку на sh-совместимую оболочку.

Bourne again shell , исполняемый файл: bash . Название можно перевести, как «Возрождённый шел Борна». Скорее всего самая популярная оболочка на сегодняшний день. Де-факто стандарт для Linux. Не буду на ней останавливаться, т.к. в интернете много хороших статей про bash. Например вот и вот .

Z shell , исполняемый файл: zsh . Свободная современная sh-совместимая оболочка. Имеет ряд преимуществ перед bash касающихся в основном работы в интерактивном режиме. О ней на Хабре писали и
Кроме того существует довольно много оболочек попадающих в эту группу: Korn shell (ksh) и Almquist shell (ash) etc но не будем подробно на них останавливаться.

C shell

C shell , исполняемый файл: csh Командная оболочка разработанная автором vi Биллом Джоем . За основу для скриптового языка csh был взят, как понятно из названия, язык C. Т.к. на тот момент, в 1978 г., это был наиболее популярный язык программирования среди разработчиков и пользователей BSD UNIX. В настоящий момент более популярна свободная реализация csh - tcsh.

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

Условная конструкция:

Цикл вычисляющий 10 первых степеней двойки:

#!/bin/sh i=2 j=1 while [ $j -le 10 ]; do echo "2 **" $j = $i i=`expr $i "*" 2` j=`expr $j + 1` done #!/bin/csh set i = 2 set j = 1 while ($j <= 10) echo "2 **" $j = $i @ i *= 2 @ j++ end

Однако список фичь поддерживаемых свежими версиями bash, zsh и tcsh очень похож и выбор конкретной оболочки по большей части дело вкуса. С менее распространенными оболочками дело обстоит иначе. Тут различия существеннее.

Командные оболочки, базирующиеся на популярных языках программирования.

Perl Shell , исполняемый файл: psh . Оболочка сочетающая в себе функции вышеупомянутых оболочек и мощь языка Perl. Т.к. psh написана на perl она может запускаться даже на Windows. Несколько примеров использования psh:
ls | s/y/k/ # Замена c помощью регулярных выражений ls | { print ++$i, ": $_"; }q # Быстрые фильтр. Внутри фигурных скобок выражение на perl, где $_ содержит одну строку вывода. netstat | { $_>2; }g # grep-фильтры. Выводятся только те строки для которых выражение в скобках возвращает true command >[=FOO] # Перенаправление по дескриптору открытого файла command > file # Эквивалентно command 2> file на bash. Перенаправляет в файл поток вывода и ошибок grep foo lib/**/*.pm # Использование **, что означает текущий каталог и все подкаталоги

Scsh , исполняемый файл scsh . Командный интерпретатор с открытым кодом использующий в качестве скриптового языка Scheme 48. Не поддерживает стандартные для других оболочек функции (история команд, редактирование текста в командной строке, дополнение путей/команд). Рекомендуется написания скриптов, но не для интерактивной работы. Может прийтись по вкусу любителям функционального программирования. Ниже приведен пример скрипта, который выводит имена всех исполняемых файлов находящихся в каталогах из переменной окружения PATH
#!/usr/local/bin/scsh -s !# (define (executables dir) (with-cwd dir (filter file-executable? (directory-files dir #t)))) (define (writeln x) (display x) (newline)) (for-each writeln (append-map executables ((infix-splitter ":") (getenv "PATH"))))

IPython . Это интерактивная оболочка для языка программирования Python, имеющая ряд дополнительных функций. IPython имеет специальный профиль для работы в качестве системной командной оболочки. Способ запуска этого режима зависит, как я понял, от версии, но на моей машине это выглядит так:
ipython3 --profile=pysh

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

  • Кросплатформенность. Есть даже версия под Windows
  • Python версий 2.x или 3.x в качестве скриптового языка, расширенные возможности интроспекции
  • Автодополнение кода Python а так же имен файлов и системных команд.
  • История команд и макросы на ее основе
  • Механизм ускоряющий навигацию по каталогам, закладки и многое другое
Как видите, по своим интерактивным возможностям IPython как минимум не уступает bash. Что же касается скриптов, то IPython будет удобен тем, кто знает python лучше чем bash. По сути скрипты на IPython будут отличаться от чистого питона только упрошенным вызовом системных команд. Приведу несколько примеров интеграции python и системных команд:
# Допустим нам захотелось посчитать сумарный размер файлов логов dpkg: In : cd /var/log/ /var/log In : log_files = !ls -l dpkg.log* In : log_files Out: "-rw-r--r-- 1 root root 1824 нояб. 3 16:41 dpkg.log" In : for line in log_files: ....: size += int(line.split()) ....: In : size Out: 1330009 # ... или последовательно пингануть десяток хостов In : for i in range(100,110): ....: !ping -c 1 192.168.0.$i ....:
Остальные
Конечно это не полный список даже популярных оболочек. Помимо вышеперечисленных категорий существуют ещё использующие собственный синтаксис, не совместимый с sh и не копирующий существующие ЯП. Примером может служить friendly interactive shell (fish) . Но на последок хотел бы рассказать не о ней, а более специфической sleepshell.

Sleep Dummy Shell , исполняемый файл: sleepshell . Строго говоря командным процессором sleepshell назвать нельзя, т.к. он не умеет обрабатывать команды. И вообще не умеет ничего, кроме как периодически записывать в стандартный вывод звёздочки "*". Однако используется она именно в качестве командной оболочки и вот для чего: Допустим мы хотим предоставить кому-то возможность делать тоннели ssh через наш сервер под управлением Linux или Unix. Подробнее про ssh-туннелирование читаем . Но нам не нужно при этом, что этот кто-то получил доступ к командной строке и файловой системе нашего сервера. Для такого случая и предназначена sleepshell. Создаем на сервере аккаунт в качестве шела для него устанавливаем sleepshell. Владелец аккаунта сможет подключаться и пробрасывать порты, но не сможет выполнять команды.

На этом всё. Надеюсь, что было интересно. Буду рад любым замечаниям и советам по тексту статьи.

Ссылки по теме
www.faqs.org/faqs/unix-faq/shell/shell-differences - сводная таблица различий и сходств командных оболочек
www.mariovaldez.net/software/sleepshell - Sleep Dummy Shell
ipython.org/ipython-doc/dev/interactive/shell.html - IPython as a system shell
www.opennet.ru/base/dev/ipython_sysadmin.txt.html - Оболочка IPython как инструмент системного администратора


Top