Перейти к основному содержанию
Рецепты Linux

Main navigation

  • Основы
  • Система
  • Команды
  • Программы
  • Дистро
  • Интерфейсы
  • Устройства
  • Доки
User account menu
  • Войти

Строка навигации

  1. Главная
  2. Linux: Введение
  3. Возможности командной оболочки

Язык программирования sh

Некогда Мефодий выучил несколько языков программирования, и уже собрался было написать кое-какие нужные программы на Си или Python, однако Гуревич его остановил. Большая часть того, что нужно начинающему пользователю Linux, делается с помощью одной правильной команды, или вызовом нескольких команд в конвейере. От пользователя только требуется оформить решение задачи в виде сценария на shell. На самом же деле уже самый первый из командных интерпретаторов, sh, был настоящим высокоуровневым языком программирования — если, конечно, считать все утилиты системы его операторами. При таком подходе от sh требуется совсем немного: возможность вызывать утилиты, возможность свободно манипулировать результатом их работы и несколько алгоритмических конструкций (условия и циклы).

К сожалению, программирование на shell, а также и других, более мощных интерпретируемых языках в Linux, не помещается в рамки нашего курса. Так что, пока Мефодий читает документацию по bash и самозабвенно упражняется в написании сценариев, нам остаётся только поверхностно рассмотреть свойства shell как языка программирования и интегратора команд. Заметим попутно, что писать сценарии для bash — непрактично, так как исполняться они смогут лишь при помощи bash. Если же ограничить себя рамками sh, совместимость с которым объявлена и в bash, и в zsh, и в ash (наиболее близком к sh по возможностям), и в других командных интерпретаторах, выполняться эти сценарии смогут любым из sh-подобных интерпретаторов, и не только в Linux.

Интеграция процессов

Каждый процесс Linux при завершении передаёт родительскому код возврата (exit status), который равен нулю, если процесс считает, что его работа была успешной, или номеру ошибки в противном случае. Командный интерпретатор хранит код возврата последней команды в специальной переменной «?». Что более важно, код возврата используется в условных операторах: если он равен нулю, условие считается выполненным, а если нет — невыполненным:

[methody@localhost methody]$ grep Methody bin/script 
echo 'Hello, Methody!'
[methody@localhost methody]$ grep -q Methody bin/script ; echo $?
0
[methody@localhost methody]$ grep -q Shogun bin/script ; echo $?
1
[methody@localhost methody]$ if grep -q Shogun bin/script ; then echo "Yes"; fi
[methody@localhost methody]$ if grep -q Methody bin/script ; then echo "Yes"; fi        
Yes

Пример 14. Оператор if использует код возврата программы grep

Условный операторif запускает команду-условие, grep -q, которая ничего не выводит на экран, зато возвращает 0, если шаблон найден, и 1, если нет. В зависимости от кода возврата этой команды, if выполняет или не выполняет тело: список команд, заключённый между then и fi. Точка с запятой разделяет операторы в sh; либо она, либо перевод строки необходимы перед then и fi, иначе всё, что идёт после grep интерпретатор посчитает параметрами этой утилиты.

Множеством функций обладает команда test: она умеет сранивать числа и строки, проверять ярлык объекта файловой системы и наличие самого этого объекта. У «test» есть второе имя: «[» (как правило, /usr/bin/[ — символьная или даже жёсткая ссылка на /usr/bin/test), позволяющее оформлять оператор if более привычным образом:

[methody@localhost methody]$ if test -f examples ; then ls -ld examples ; fi
[methody@localhost methody]$ if [ -d examples ] ; then ls -ld examples ; fi
drwxr-xr-x  2 methody methody 4096 Окт 31 15:26 examples
[methody@localhost methody]$ A=8; B=6; if [ $A -lt $B ] ; then echo "$A<$B" ; fi
[methody@localhost methody]$ A=5; B=6; if [ $A -lt $B ] ; then echo "$A<$B" ; fi
5<6

Пример 15. Оператор test

Команда test -f проверяет, на является ли её аргумент файлом; поскольку examples — это каталог, результат — неуспешный. Команда [ -d — то же самое, что и test -d (не каталог ли первый параметр), только последним параметром этой команды — исключительно для красоты — должен быть символ «]». Результат — успешный, и выполняется команда ls -ld. Команда test параметр1 -lt параметр3 проверяет, является ли параметр1 числом, меньшим, чем (less then) параметр3. В более сложных случаях оператор if удобнее записывать «лесенкой», выделяя переводами строки окончане условия и команды внутри тела (их может быть много).

Второй тип подстановки, которую shell делает внутри двойных кавычек — это подстановка вывода команды. Подстановка вывода имеет вид «`команда`» (другой вариант — «$(команда)»). Как и подстановка значения переменной, она происходит перед тем, как начнётся разбор командной строки: выполнив команду и получив от неё какой-то текст, shell примется разбирать его, как если бы этот текст пользователь набрал вручную. Это очень удобное средство, если то, что выводит команда, необходимо передать самому интерпретатору:

[methody@localhost methody]$ A=8; B=6
[methody@localhost methody]$ expr $A + $B
14
[methody@localhost methody]$ echo "$A + $B = `expr $A + $B`"
8 + 6 = 14
[methody@localhost methody]$ A=3.1415; B=2.718
[methody@localhost methody]$ echo "$A + $B = `expr $A + $B`"
expr: нечисловой аргумент
3.1415 + 2.718 = 
[methody@localhost methody]$ echo "$A + $B" | bc
5.8595
[methody@localhost methody]$ C=`echo "$A + $B" | bc`
[methody@localhost methody]$ echo "$A + $B = $C"
3.1415 + 2.718 = 5.8595

Пример 16. Подстановка вывода команды

Сначала для арифметических вычислений Мефодий хотел воспользоваться командой expr, которая работает с параметрами командной строки. С целыми числами expr работает неплохо, и её результат можно подставить прямо в аргумент команды echo. С действительными числами умеет работать утилита-фильтрbc; арифметическое выражение пришлось сформировать с помощью echo и передать по конвейеру, а резутьтат — поместить в переменную C. Во многих современных командных оболочках есть встроенная целочисленная арифметика вида «$(( выражение ))».

Сценарии

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

[methody@localhost methody]$ cat > bin/two
#!/bin/sh
echo "Running $0: $*"
$1 $3
$2 $3
[methody@localhost methody]$ chmod +x bin/two
[methody@localhost methody]$ bin/two file "ls -ld" examples
Running bin/two: file ls -ld examples
examples: directory
drwxr-xr-x  2 methody methody 4096 Окт 31 15:26 examples
[methody@localhost methody]$ two "ls -s" wc "bin/two bin/loop" junk
Running /home/methody/bin/two: ls -s wc bin/two bin/loop junk
4 bin/loop  4 bin/two
 4  9 44 bin/two
 1  5 26 bin/loop
 5 14 70 итого

Пример 17. Использование позиционных параметров в сценарии

Как видно из примера, форма «$номер_параметра» позволяет обратиться и к нулевому параметру — команде, а вся строка переметров хранится в переменной «*». Кроме того, свойство подстановки выполняться до разбора командной строки позволило Мефодию передать в качестве одного параметра "ls -ld" или "bin/two bin/loop", а интерпретатору — разбить эти параметры на имя команды и ключи и два имени файла соответственно.

В sh есть и оператор циклаwhile, формат которого аналогичен if, и более удобный именно в сценариях оператор обхода списка for (список делится на слова так же, как и командная строка — с помощью разделителей):

[methody@localhost methody]$ for Var in Wuff-Wuff Miaou-Miaou; do echo $Var; done
Wuff-Wuff
Miaou-Miaou
[methody@localhost methody]$ for F in `date`; do echo -n "<$F>"; done; echo
<Сбт><Ноя><6><12:08:38><MSK><2004>
[methody@localhost methody]$ cat > /tmp/setvar
QWERTY="$1"
[methody@localhost methody]$ sh /tmp/setvar 1 2 3; echo $QWERTY

[methody@localhost methody]$ . /tmp/setvar 1 2 3; echo $QWERTY
1

Пример 18. Использование for и операции «.»

Во втором for Мефодий воспользовался подстановкой вывода команды date, каждое слово которой вывел с помощью echo -n в одну строку, а в конце команды пришлось вывести один перевод строки вручную.

Вторая половина примера иллюстрирует ситуацию, с которой Мефодий столкнулся во время своих экспериментов: все переменные, определяемые в сценарии, куда-то пропадают после окончания его работы. Оно и понятно: для обработки сценария всякий раз запускается новый интерпретатор (дочерний процесс!), и все его переменные принадлежат именно ему и с завершением процесса уничтожаются. Таким образом достигается отсутствие побочных эффектов: запуская программу, пользователь может быть уверен, что та не изменит окружения командной оболочки. Однако в некоторых случаях требуется обратное: запустить сценарий, который нужным образом настроит окружение. Единственный выход — отдавать такой сценарий на обработку текущему, а не новому, интерпретатору (т. е. тому, что разбирает команды пользователя). Это и делается с помощью специальной команды «.». Если вдруг в передаваемом сценарии обнаружится команда exit, exec или какая-нибудь другая, приводящая к завершению работы интерпретатора, завершится именно текущая командная оболочка, чем сеанс работы пользователя в системе может и закончиться.

Перекрёстные ссылки книги для Язык программирования sh

  • Окружение
  • Вверх
  • Настройка командного итерпретатора

Book navigation

  • Предисловие
  • Сеанс работы в Linux
  • Терминал и командная строка
  • Структура файловой системы
  • Работа с файловой системой
  • Доступ процессов к файлам и каталогам
  • Права доступа
  • Работа с текстовыми данными
  • Возможности командной оболочки
    • Редактирование ввода
    • Генерация имён файлов
    • Окружение
    • Язык программирования sh
    • Настройка командного итерпретатора
  • Текстовые редакторы
  • Этапы загрузки системы
  • Работа с внешними устройствами
  • Конфигурационные файлы
  • Управление пакетами
  • Сеть TCP/IP в Linux
  • Сетевые и серверные возможности
  • Графический интерфейс (X11)
  • Прикладные программы
  • Политика свободного лицензирования

Последние материалы

  • Файл sudoers
    11 hours ago
  • Утилита visudo
    1 day 18 hours ago
  • Файловый менеджер Thunar
    1 week 4 days ago
  • Эмулятор терминала Terminator
    2 weeks 2 days ago
  • Приложение scanimage
    3 weeks 1 day ago
RSS feed

Secondary menu

  • О проекте

© 2008–2025 Олег Меньшенин mensh@yandex.ru