Shell: язык программирования и оболочка.
Лектор не рассказывал обо всех утилитах, но дал представление о том, что если мы находимся в рамках парадигмы черного ящика, то инструментальное окружение достаточно универсально. Тут возникает важный вопрос - о суперпозиции инструментов. Не хватало главного - каким образом инструменты могут быть задействованы для решения глобальных задач. Для этой цели должен быть предусмотрен инструмент для интеграции раздельный утилит и управления ими - оболочка: * манипуляция с системными объектами из одного и того же места - сценарии * работа с файлами, процессами, утилитами * работа с данными, которые обрабатываются, работа с потоками данных На самом деле, нам нужен не просто костыль для складывания команд в сценарии. Нужен язык программирования, который хорошо для этого заточен. из этого следует подход к шеллу, как к языку программирования. Но он должен быть: * алгоритмически полным.
Сценарий -- запись кс в виде файла. Надо поддерживать дисциплину, когда забиваем кс и оно работает.
3 св-во -- он должен быть достаточно высокоуровневый. На взгляд высоко и низко уровневые языки отличаются кол-вом кода(сравни си, питон, хаскель). Требование высокоуровевости говорит о том, что там должно быть как можно меньше мусора, потому что оно для решения интеграц задач, а не больших проектов.
Интерпретатор командной строки -- икс (игрека в этой лекции нет) -- он интерпретирует ком. строку, а ещё люди в нём работают, то есть он взаимодействует с пользователем, и должен это делать удобно для пользователя. Третье лектор пока не знает.
На самом деле представляется чистой случайностью, что оболочка, яп и икс стали одним инструментом под названием шелл. Исторически это неслучайно. Комбайнов в линуксе много (напр, пакетный установщик пакет не только ставит, но и собирает). Под эту базу можно и фразу подвести. Только реализуя все три функции в одном инструменте можно обеспечить полноценность каждого. Например, в досе синтаксис работы в кс и бат файлов различается, и иногда в сценарии можно то, что нельзя в кс. Это плохо. В бат ничего нельзя было делать, только извращения. Он был не алгоритмически полон(?).
Одновременно совместимость инструментальная и интерфейсная. Другие оболочки(цмд) это нарушают и делают себя маргинализованными. Шелл же универсален.
Шелл как язык программирования
Что мы знаем про сценарии в линуксе/юниксе? Это файл с # в начале, например
#!/bin/sh
Началось все с механизма запуска текстовых файлов. Шелл -- интерпретируемый яп.
Переменные
В шелле все строковые. A=B и в переменную кладется строка. Свойство оболочности добавляет интересный отпечаток. Переменную можно экспортиироовать, и она станет переменной окружения export A=BC.
Про переменные окружения -- можно управлять работой программы ключами каждой раз при запуске, но иногда удобно использовать переменные окружения COLUMNS PATH. После экспорта любой процесс может видеть эти переменные через getenv. Экспортные переменные -- аналог глобальных между скриптами.
У операции присваивания есть левая и правая часть. В правой части строки выглядят просто(без кавычек) а вот чтобы получить содержимое переменной с заданным именем надо приписывать в начале $. echo $A. "У теоретических программистов, например, принято перечеркивать не нолик, а букву о"(с)
Если вы пишете скрипт на шелле, вы ему можете передавать параметры ком строки. $0, $1, $2, $* -- первый, второй, третий, все кроме нулевого. Ещё есть эзотерический $@. Он отдает "$1" "$2" "$3" и тд. $* -- все одной строкой.
В шелле вобще много разного для удобства и не очень красивое с тз теории.
Количество параметров ком строки $#. Exit status предыдущего процесса хранится в $?. Это часть интеграторская.
Возвращаясь к теме шелл как интерпретатор -- обратите как легко и непринужденно в шелле запускать фоновые процессы. Запуск фонового процесса -- один символ, амперсанд в конце.
$!
$$
и ещё 100500.
Помимо самих операций подстановки в шелле есть куча подставлений переменных с последующей обработкой. Допустим надо вынуть начало строчки до точки. Как вы будете делать? подключите библиотеку, сделаете сплит по разделителю, возьмете нулевое. Можно вызвать внешнюю утилиту, но каждый раз --- вызывалка отвалится. ${VAR#*.} -- отрубить самый длинный хвост начинающийся с точки. Есть отрубание хвоста, головы и ещё много чего.
Всё это есть в справочниках по шеллу. Подстановка значений переменных в шелле сопровождается обработкой. В итоге в небольшом тексте можно достигнуть своих целей. (пример -- отрывание расширения)
Завязываемся на объекты с опр структурой -- имена файлов.
Отдельно к свойствам оболочки можно отнести подстановку результата вывода программы. i = $(ls) или i = ls. Перевод из потоков данных в переменные. КАк ещё можно манипулировать результатами работы программы. Перенаправлением ввода-вывода в файлы. ls > file, wc < file. А вот << это совсем другое -- спецификация входного потока в сценарии. (подать на ввод что-то от ограничителя до ограничителя, например). Ещё при такой обработке будет работать подставновка переменных. '$A' -> $A, "$A"->содержимое А.
Тут просто закрыли дескриптор, открыли в файл.
Интересней cal | wc (cal pipeline wc) . В позикс системах существуют пайпы -- каналы. Один пишет, другой читает. С тз пользователя -- программа wc обработала вывод команды cal.
Дерево трубопровода в одной строчке задать нельзя.
В позикс окружении очень много программ, которые читают с ст ввода, пишут в ст. вывод, именно потому, что их всегда можно перенаправить
Условные операторы, циклы и нет goto
if command; then command; [else command;] fi
fi операторная скобка (esac тоже).
Обратите внимания, что на месте условия стоит команда. Если последняя в цепочке команд выполнилась успещно(вернула 0), то это истина, а иначе ложь.
В итоге шелл может вообще ничего не уметь, а какая-нибудь команда умеет сравнивать, и вообще. Эта команда [. Лежит в sbin, симлинк test.
if [ "$a" ='QQ' ]; then
после [ обязателен пробел, потому что она команда.
a = eval 1+$a
Это ещё один щтрих к портрету шелла как оболочки. Если что-то может быть реализовано внешне, то оно выносится.
Но евал нетипичен, слишком часто нужен. Почти все шеллы обзавелись собственной арифметикой, а некоторые и логикой.
Тест тоже встроенный уже.
Цикл while do done
Цикл for по списку. for переменная in список; do command; done
Отдельную забавную вариацию составляет цикл for nep; Переменная пробегает значения $1 $2 $3 итд.
Про то, чем отличаются шеллы -- в след раз.
Если есть простая алг. задача (сгенерировать список от 1 до 100) то скорее всего есть утилита, которая её решает (seq).
Функции
Это просто функции, у них ничего такого нету.
1) они возвращают код возврата, а не строку. если хотите из неё что-то вернуть -- надо в ней ставить эхо, а вызов заключить в бэктик.
2)
lls(){
$1 $2 -- параметры функции
}
Функции ведут себя как утилиты, даже внутри у них разбор устроен таким образом, что они работают с позиционными параметрами.
В шелле есть обработка сигналов(можно обрабатывать CTRL-c)
ВВод-вывод
Упрощён.
read считывает по строчке со стандартного ввода. Возвращает неноль, когда заканчивается ввод.
Чего в шелле нету?
Определения собственных типов данных.
Составления графов потоков -- только через файлы.
Никакой интерфейсной поддержки кроме командной строки. Игры и граф интерфейсы на шелле - удаль молодецкая (хоть лектор и писал), он не для этого.
Шелл это хорошая оболочка для того чтобы организовывать интеграцию(алг полную) в рамках концепции инструментального окружения.