355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Нейл Мэтью » Основы программирования в Linux » Текст книги (страница 5)
Основы программирования в Linux
  • Текст добавлен: 21 сентября 2016, 17:59

Текст книги "Основы программирования в Linux"


Автор книги: Нейл Мэтью


Соавторы: Ричард Стоунс
сообщить о нарушении

Текущая страница: 5 (всего у книги 67 страниц)

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

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

Интерактивные программы

Легкий и очень полезный во время обучения или тестирования способ проверить работу небольших фрагментов кода – просто набрать с клавиатуры в командной строке сценарий командной оболочки.

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

$ for file in *

> do

> if grep -l POSIX $file

> then

> more $file

> fi

> done

posix

This is a file with POSIX in it – treat it well

$

Обратите внимание на то, как меняется знак $, стандартная подсказка или приглашение командной оболочки, на символ >, когда оболочка ожидает очередной ввод. Вы можете продолжить набор, дав оболочке понять, когда закончите, и сценарий немедленно выполнится.

В этом примере команда grep выводит на экран найденные ею имена файлов, содержащих строку POSIX, а затем команда more отображает на экране содержимое файла. В конце на экран возвращается приглашение командной оболочки. Обратите внимание также на то, что вы ввели переменную командной оболочки, которая обрабатывает каждый файл для самодокументирования сценария. С таким же успехом вы могли бы использовать переменную i, но имя file более информативно с точки зрения пользователей.

Командная оболочка также обрабатывает групповые символы или метасимволы (часто называемые знаками подстановки). Вы почти наверняка знаете о применении символа * как знака подстановки, соответствующего строке символов. Но вы можете не знать о существовании односимвольного знака подстановки, ?, а конструкция [set] позволяет проверить любое количество одиночных символов, [^set] – применяет логическую операцию «НЕ» к множеству, т.е. включает все, кроме того, что вы задали. Подстановочный шаблон из фигурных скобок {} (доступен в некоторых командных оболочках, включая bash) позволяет формировать множество из произвольных строк, которое командная оболочка раскроет. Например, команда

$ ls my_{finger, toe}s

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

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

$ more `grep -l POSIX *`

или синонимической конструкции

$ more $(grep -l POSIX *)

В дополнение команда

$ grep -l POSIX * | more

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

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

Создание сценария

С помощью любого текстового редактора необходимо создать файл, содержащий команды. Создайте файл с именем first с таким содержимым:

#!/bin/sh

# first

# Этот файл просматривает все файлы в текущем каталоге

# для поиска строки POSIX, а затем выводит имена

# найденных файлов в стандартный вывод.

for file in *

do

 if grep -q POSIX $file

 then

  echo $file

 fi

done

exit 0

Комментарий начинается со знака # и продолжается до конца строки. Принято знак # ставить в первой символьной позиции строки. Сделав такое общее заявление, далее отметим, что первая строка #!/bin/sh – это особая форма комментария; символы #! сообщают системе о том, что следующий за ними аргумент – программа, применяемая для выполнения данного файла. В данном случае программа /bin/sh – командная оболочка, применяемая по умолчанию.

Примечание

Обратите внимание на абсолютный путь, заданный в комментарии. Принято сохранять его длиной не более 32 символов для обратной совместимости, поскольку некоторые старые версии ОС UNIX могут использовать только такое ограниченное количество символов в комментарии #!, хотя у ОС Linux обычно нет подобного ограничения.

Поскольку сценарий по существу обрабатывается как стандартный ввод командной оболочки, он может содержать любые команды ОС Linux, на которые ссылается переменная окружения PATH.

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

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

В сценарии не используются никакие расширения и суффиксы имен файлов; ОС Linux и UNIX, как правило, редко применяют при именовании файлов расширения для указания типа файла. Вы могли бы использовать расширение sh или любое другое, командную оболочку это не волнует. У большинства предустановленных сценариев нет никакого расширения в именах файлов и лучший способ проверить, сценарий это или нет применить команду file, например, file first или file /bin/bash. Пользуйтесь любыми правилами, принятыми в вашей организации или удобными для вас.

Превращение сценария в исполняемый файл

Теперь, когда у вас есть файл сценария, его можно выполнить двумя способами. Более простой путь – запустить оболочку с именем файла сценария как параметром:

$ /bin/sh first

Этот вариант будет работать, но гораздо лучше запускать сценарий, введя его имя и тем самым присвоив ему статус других команд Linux. Сделаем это с помощью команды chmod, изменив режим файла (file mode) и сделав его исполняемым для всех пользователей:

$ chmod +х first

Примечание

Конечно, превращение файла в исполняемый – это не единственный вариант применения команды chmod. Для того чтобы узнать больше о восьмеричных аргументах и других опциях команды, наберите man chmod.

После этого вы можете выполнять файл с помощью команды

$ first

При этом может появиться сообщение об ошибке, говорящее о том, что команда не найдена. Почти наверняка причина в том, что в переменной PATH не задан текущий каталог для поиска выполняемых команд. Исправить это можно либо введя с клавиатуры в командной строке PATH=$PATH:., либо добавив данную команду в конец файла .bash_profile. Затем выйдите из системы и зарегистрируйтесь снова. В противном случае введите ./first в каталог, содержащий сценарий, чтобы задать командной оболочке полный относительный путь к файлу.

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

Примечание

Не следует вносить подобные изменения в переменную PATH для суперпользователя, как правило, с именем root. Это лазейка в системе безопасности, т.к. системного администратора, зарегистрировавшегося как root, обманным путём могут заставить запустить фиктивную версию стандартной команды. Один из авторов однажды разрешил сделать это – конечно только для того, чтобы поставить перед системным администратором вопрос о безопасности! В случае обычных учетных записей включение текущего каталога в полный путь сопряжено с очень небольшим риском, поэтому, если вам это нужно, примите за правило добавление комбинации символов ./ перед всеми командами, находящимися в локальном каталоге.

После того как вы убедитесь в корректной работе вашего сценария, можете переместить его в более подходящее место, чем текущий каталог. Если команда предназначена только для собственных нужд, можете создать каталог bin в своем исходном каталоге и добавить его в свой путь. Если вы хотите, чтобы сценарий выполняли другие пользователи, можно использовать каталог /usr/local/bin или другой системный каталог как удобное, хранилище для вновь созданных программ. Если в вашей системе у вас нет прав суперпользователя, можно попросить системного администратора скопировать ваш файл для вас, хотя сначала, возможно, придется убедить его в неоспоримых достоинствах вашего файла. Для того чтобы установить владельца и права доступа к файлу, администратору придется задать такую последовательность команд:

# ср first /usr/local/bin

# chown root /usr/local/bin/first

# chgrp root /usr/local/bin/first

# chmod 755 /usr/local/bin/first

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

Если захотите, можно применить более длинную, но более понятную форму команды chmod:

# chmod u=rwx, go=rx /usr/local/bin/first

Более подробную информацию можно найти в справочном руководстве команды chmod.

Примечание

В ОС Linux вы можете удалить файл, если у вас есть право записи в каталог, содержащий этот файл. Для безопасности убедитесь в том, что право записи в каталоги, содержащие файлы, которые вы хотели бы защитить, есть только у суперпользователя. В этом есть смысл, потому что каталог – это всего лишь еще один файл, и наличие права записи в файл каталога позволяет пользователям добавлять и удалять имена.

Синтаксис командной оболочки

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

□ переменные: строки, числа, переменные окружения и параметры;

□ условия: булевы или логические выражения (Booleans);

□ управление выполнением программы: if, elif, for, while, until, case;

□ списки;

□ функции;

□ команды, встроенные в командную оболочку;

□ получение результата выполнения команды;

□ встроенные (here) документы.

Переменные

В командной оболочке переменные перед применением обычно не объявляются. Вместо этого вы создаете их, просто используя (например, когда присваиваете им начальное значение). По умолчанию все переменные считаются строками и хранятся как строки, даже когда им присваиваются числовые значения. Командная оболочка и некоторые утилиты преобразуют строки, содержащие числа, в числовые значения, когда нужно их обработать должным образом. Linux – система, чувствительная к регистру символов, поэтому командная оболочка считает foo и Foo двумя разными переменными, отличающимися от третьей переменной FOO.

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

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

$ salutation=Hello

$ echo $salutation

Hello

$ salutation="Yes Dear"

$ echo $salutation

Yes Dear

$ salutation=7+5

$ echo $salutation

7+5

Примечание

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

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

$ read salutation

Wie geht's?

$ echo $salutation

Wie geht's?

Заключение в кавычки

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

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

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

Выполним упражнение 2.1.

Упражнение 2.1. Игра с переменными

В этом упражнении показано, как кавычки влияют на вывод переменной:

#!/bin/sh

myvar="Hi there"

echo $myvar

echo «$myvar»

echo '$myvar'

echo $myvar

echo Enter some text

read myvar

echo '$myvar' now equals $myvar

exit 0

Данный сценарий ведет себя следующим образом:

$ ./variable

Hi there

Hi there

$myvar

$myvar

Enter some text

Hello World

$myvar now equals Hello World

Как это работает

Создается переменная myvar, и ей присваивается строка Hi there. Содержимое переменной выводится на экран с помощью команды echo, демонстрирующей, как символ $ раскрывает содержимое переменной. Вы видите, что применение двойных кавычек не влияет на раскрытие содержимого переменной, а одинарные кавычки и обратный слэш влияют. Вы также применяете команду read для получения строки от пользователя.

Переменные окружения

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

Таблица 2.2


$НОМЕ Исходный каталог текущего пользователя
$PATH Разделенный двоеточиями список каталогов для поиска команд
$PS1 Подсказка или приглашение командной строки. Часто знак $, но в оболочке bash можно применять и более сложные варианты. Например, строка [u@h w]$ – популярный стандарт, сообщающий в подсказке пользователя имя компьютера и текущий каталог, а также знак $
$PS2 Дополнительная подсказка или приглашение, применяемое как приглашение для дополнительного ввода; обычно знак >
$IFS Разделитель полей ввода. Список символов, применяемых для разделения слов при чтении оболочкой ввода, как правило, пробел, знак табуляции и символ перехода на новую строку
$0 Имя сценария командной оболочки
$# Количество передаваемых параметров
$$ ID (идентификатор) процесса сценария оболочки, часто применяемый внутри сценария для генерации уникальных имен временных файлов; например, /tmp/tmpfile_$$

Примечание

Если вы хотите проверить с помощью команды env <команда>, как работает программа в разных окружениях, познакомьтесь с интерактивным справочным руководством к команде env. Далее в этой главе вы увидите, как задавать переменные окружения в подоболочках (subshells), применяя команду export.

Переменные-параметры

Если ваш сценарий вызывается с параметрами, создается несколько дополнительных переменных. Если параметры не передаются, переменная окружения $# все равно существует, но равна 0.

Переменные-параметры перечислены в табл. 2.3.

Таблица 2.3


$1, $2, ...Параметры, передаваемые сценарию
$* Список всех параметров в единственной переменной, разделенных первым символом из переменной окружения IFS. Если IFS корректируется, способ разделения командной строки на параметры в переменной $* изменяется
$@ Едва различимая вариация $*; не использует переменную окружения IFS, поэтому параметры не сольются, даже если переменная IFS пуста

Легче всего увидеть разницу между переменными-параметрами $* и $@, опробовав их.

$ IFS=''

$ set foo bar bam

$ echo «$@»

foo bar bam

$ echo «$*»

foobarbam

$ unset IFS

$ echo «$*»

foo bar bam

Как видите, заключенная в двойные кавычки переменная-параметр $@ представляет позиционные параметры как отдельные поля, независимо от значения переменной окружения IFS. Как правило, если вы хотите получить доступ к параметрам, лучше использовать переменную-параметр.

Помимо вывода на экран содержимого переменных с помощью команды echo, вы также можете прочитать его командой read (упражнение 2.2).

Упражнение 2.2. Манипулирование параметрами и переменными окружения

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

#!/bin/sh

salutation="Hello"

echo $salutation

echo «The program $0 is now running»

echo «The second parameter was $2»

echo «The first parameter was $1»

echo "The parameter list was

echo «The user's home directory is $HOME»

echo «Please enter a new greeting»

read salutation

echo $salutation

echo «The script is now complete»

exit 0

Если вы выполните этот сценарий, то получите следующий вывод:

$ ./try_var foo bar baz

Hello

The program ./try_var is now running

The second parameter was bar

The first parameter was foo

The parameter list was foo bar baz

The user's home directory is /home/rick

Please enter a new greeting

Sire

Sire

The script is now complete $

Как это работает

Сценарий создает переменную salutation, выводит на экран ее содержимое и затем показывает, что уже сформированы и имеют соответствующие значения различные переменные-параметры и переменная окружения $НОМЕ.

Далее в этой главе мы рассмотрим более подробно подстановку параметров.

Условия

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

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

Команда test или [

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

Примечание

Эти команды в некоторых ранних оболочках UNIX вызывают внешнюю программу, но в более современных версиях их стараются делать встроенными. Мы вернемся к этому, когда будем рассматривать команды в следующем разделе.

Поскольку команда test не часто применяется за пределами сценариев командной оболочки, многие пользователи ОС Linux, никогда раньше не писавшие сценариев, пытаются создавать простые программы и называют их test. Если такая программа не работает, вероятно, она конфликтует с командой оболочки test. Для того чтобы выяснить, есть ли в вашей системе внешняя команда с данным именем, попытайтесь набрать что-нибудь вроде which test и проверить, какая именно команда test выполняется в данный момент, или используйте форму ./test, чтобы быть уверенным в том, что вы выполняете сценарий из текущего каталога. Если сомневаетесь, примите за правило выполнять свои сценарии, предваряя при запуске их имена комбинацией символов ./.

Мы представим команду test на примере одного простейшего условия: проверки наличия файла. Для нее понадобится следующая команда: test -f <имя_файла>, поэтому в сценарии можно написать

if test -f fred.c

then

 ...

fi

To же самое можно записать следующим образом:

if [ -f fred.c ]

then

 ...

fi

Код завершения команды test (выполнено ли условие) определяет, будет ли выполняться условный программный код.

Примечание

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

Если вы предпочитаете помещать слово then в той же строке, что и if, нужно добавить точку с запятой для отделения команды test от then:

if [ -f fred.c ]; then

 ...

fi

Варианты условий, которые вы можете применять в команде test, делятся на три типа: строковые сравнения, числовые сравнения и проверка файловых флагов (file conditionals). Эти типы условий описаны в табл. 2.4.

Таблица 2.4


Строка1 = Строка2 True (истина), если строки одинаковы
Строка1 != Строка2 True (истина), если строки разные
-n Строка True (истина), еслиСтрока не null
-z Строка True (истина), еслиСтрока null (пустая строка)
Выражение1 -eq Выражение2 True (истина), если выражения равны
Выражение1 -ne Выражение2 True (истина), если выражения не равны
Выражение1 -gt Выражение2 True (истина), еслиВыражение1 больше, чемВыражение2
Выражение1 -ge Выражение2 True (истина), еслиВыражение1 не меньшеВыражение2
Выражение1 -lt Выражение2 True (истина), еслиВыражение1 меньше, чемВыражение2
Выражение1 -lе Выражение2 True (истина), еслиВыражение1 не большеВыражение2
! Выражение True (истина), еслиВыражение ложно, и наоборот
-d файл True (истина), еслифайл– каталог
файл True (истина), еслифайл существует. Исторически, опция -e не была переносима на другие платформы, поэтому обычно применяется -f
-f файл True (истина), еслифайл– обычный файл
-g файл True (истина), если дляфайла установлен бит set-group-id
-r файл True (истина), если файл доступен для чтения
-s файл True (истина), если файл ненулевого размера
-u файл True (истина), если дляфайла установлен бит set-user-id
-v файл True (истина), еслифайл доступен для записи
файл True (истина), если файл – исполняемый файл

Примечание

Вас могли заинтересовать непонятные биты set-group-id и set-user-id (также называемые set-gid и set-uid). Бит set-uid предоставляет программе права владельца, а не просто ее пользователя, бит set-gid предоставляет программе права группы. Эти биты устанавливаются командой chmod с помощью опций s и g. На файлы, содержащие сценарии, флаги set-gid и set-uid не влияют, они оказывают влияние только на исполняемые двоичные файлы.

Мы немного сами себя обогнали, но далее следует пример тестирования состояния файла /bin/bash, так что вы сможете увидеть, как это выглядит на практике.

#!/bin/sh

if [ -f /bin/bash ]

then

 echo «file /bin/bash exists»

fi

if [ -d /bin/bash ]

then

 echo «/bin/bash is a directory»

else

 echo «/bin/bash is NOT a directory»

fi

Для того чтобы тест мог оказаться истинным, предварительно, для проверки всех файловых флагов требуется наличие файла. Данный перечень включает только самые широко используемые опции команды test, полный список можно найти в интерактивном справочном руководстве. Если вы применяете оболочку bash, в которую встроена команда test, используйте команду help test для получения дополнительных сведений. Позже в этой главе мы применим некоторые из этих опций.

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


    Ваша оценка произведения:

Популярные книги за неделю