В первой части статьи мы рассмотрели командные оболочки, профили, синонимы и первые команды. Под спойлером я также рассказал, как развернуть тестовую виртуальную машину. В этой части речь пойдет о файлах скриптов, их параметрах и правах доступа. Также я расскажу про операторы условного выполнения, выбора и циклы. Для выполнения нескольких команд одним вызовом удобно использовать скрипты. Скрипт – это текстовый файл, содержащий команды для shell. Это могут быть как внутренние команды shell, так и вызовы внешних исполняемых файлов. Как правило, имя файла скрипта имеет окончание .sh, но это не является обязательным требованием и используется лишь для того, чтобы пользователю было удобнее ориентироваться по имени файла. Для интерпретатора более важным является содержимое файла, а также права доступа к нему. Перейдем в домашнюю директорию командой cd ~ и создадим в ней с помощью редактора nano (nano script.sh)файл, содержащий 2 строки: Чтобы выйти из редактора nano после набора текста скрипта, нужно нажать Ctrl+X, далее на вопрос "Save modified buffer?" нажать Y, далее на запрос "File Name to Write:" нажать Enter. При желании можно использовать любой другой текстовый редактор. Скрипт запускается командой ./<имя_файла>, т.е. ./ перед именем файла указывает на то, что нужно выполнить скрипт или исполняемый файл, находящийся в текущей директории. Если выполнить команду script.sh, то будет выдана ошибка, т.к. оболочка будет искать файл в директориях, указанных в переменной среды PATH, а также среди встроенных команд (таких, как, например, pwd): Ошибки не будет, если выполнять скрипт с указанием абсолютного пути, но данный подход является менее универсальным: /home/user/script.sh. Однако на данном этапе при попытке выполнить созданный файл будет выдана ошибка: Проверим права доступа к файлу: Из вывода команды ls видно, что отсутствуют права на выполнение. Рассмотрим подробнее на картинке: Права доступа задаются тремя наборами: для пользователя, которому принадлежит файл; для группы, в которую входит пользователь; и для всех остальных. Здесь r, w и x означают соответственно доступ на чтение, запись и выполнение. В нашем примере пользователь (test) имеет доступ на чтение и запись, группа также имеет доступ на чтение и запись, все остальные – только на чтение. Эти права выданы в соответствии с правами, заданными по умолчанию, которые можно проверить командой umask -S. Изменить права по умолчанию можно, добавив вызов команды umask с нужными параметрами в файл профиля пользователя (файл ~/.profile), либо для всех пользователей в общесистемный профиль (файл /etc/profile). Для того, чтобы установить права, используется команда chmod <параметры> <имя_файла>. Например, чтобы выдать права на выполнение файла всем пользователям, нужно выполнить команду: Чтобы выдать права на чтение и выполнение пользователю и группе: Чтобы запретить доступ на запись (изменение содержимого) файла всем: Также для указания прав можно использовать маску. Например, чтобы разрешить права на чтение, запись, выполнение пользователю, чтение и выполнение группе, и чтение – для остальных, нужно выполнить: Будут выданы права -rwxr-xr--: Указывая 3 цифры, мы задаем соответствующие маски для каждой из трех групп. Переведя цифру в двоичную систему, можно понять, каким правам она соответствует. Иллюстрация для нашего примера: Символ – перед наборами прав доступа указывает на тип файла (– означает обычный файл, d – директория, l – ссылка, c – символьное устройство, b – блочное устройство, и т. д.). Соответствие числа, его двоичного представления и прав доступ можно представить в виде таблицы: Число Двоичный вид Права доступа 0 000 Нет прав 1 001 Только выполнение (x) 2 010 Только запись (w) 3 011 Запись и выполнение (wx) 4 100 Только чтение (r) 5 101 Чтение и выполнение (rx) 6 110 Чтение и запись (rw) 7 111 Чтение, запись и выполнение (rwx) Выдав права на выполнение, можно выполнить скрипт: Первая строка в скрипте содержит текст #!/bin/bash. Пара символов #! называется Шеба́нг (англ. shebang) и используется для указания интерпретатору, с помощью какой оболочки выполнять указанный скрипт. Это гарантирует корректность исполнения скрипта в нужной оболочке в случае, если у пользователя будет указана другая. Также в скриптах можно встретить строку #!/bin/sh. Но, как правило, /bin/sh является ссылкой на конкретный shell, и в нашем случае /bin/sh ссылается на /bin/dash, поэтому лучше явно указывать необходимый интерпретатор. Вторая строка содержит команду echo Hello!, результат работы которой мы видим в приведенном выводе. Для того, чтобы обеспечить некоторую универсальность, существует возможность при вызове передавать скрипту параметры. В этом случае вызов скрипта будет выглядеть так: <имя_скрипта> <параметр1>  <параметр2> …, например ./script1.sh Moscow Russia.  Для того, чтобы получить значение первого параметра, необходимо в скрипте указать $1, второго - $2, и т.д. Существует также ряд других переменных, значения которых можно использовать в скрипте:$0 – имя скрипта$# – количество переданных параметров$$ – PID(идентификатор) процесса, выполняющего скрипт$? – код завершения предыдущей команды Создадим файл script1.sh следующего содержания: Выдадим права на выполнение и выполним скрипт с параметрами: Мы передали 2 параметра, указывающие город и страну, и использовали их в скрипте, чтобы сформировать строку, выводимую командой printf. Также для вывода в строке Hello использовали имя пользователя из переменной USER. Для того, чтобы передать значения параметров, состоящие из нескольких слов (содержащие пробелы), нужно заключить их в кавычки: При этом нужно доработать скрипт, чтобы в команду printf параметры также передавались в кавычках: Из приведенных примеров видно, что при обращении к переменной для получения её значения используется символ $. Для того, чтобы сохранить значение переменной просто указывается её имя: Так же, как и в языках программирования, в bash существуют операторы условного выполнения – выполнение определенных действий при определенных условиях. Кроме того, существует возможность повторного выполнения определенного блока команд пока выполняется заданное условие – операторы цикла. Рассмотрим каждый из них подробнее. Оператор условного выполнения представляет собой конструкцию вида: Создадим скрипт, проверяющий длину введенной строки (например, для проверки длины пароля), которая должна быть не меньше (т.е. больше) 8 символов: Выполним 2 теста, с длиной строки 5 и 8 символов: Командой read str мы получаем значение, введенное пользователем и сохраняем его в переменную str. С помощью выражения ${#str} мы получаем длину строки в переменной str и сравниваем её с 8. Если длина строки меньше, чем 8  (-lt 8), то выдаем сообщение «String is too short», иначе – «String is ok». Условия можно комбинировать, например, чтобы указать, чтоб длина должна быть не меньше восьми 8 и не больше 16 символов, для условия некорректных строк нужно использовать выражение . Здесь || означает логическое "ИЛИ", а для логического "И" в bash используется &&. Условия также могут быть вложенными: Здесь мы сначала проверяем, что строка меньше 8 символов, отсекая минимальные значения, и выводим "String is too short", если условие выполняется. Если условие не выполняется(строка не меньше 8 символов) - идем дальше(первый else) и проверяем, что строка больше 16 символов. Если условие выполняется - выводим "String is too long", если не выполняется(второй else) - выводим "String is ok". Результат выполнения тестов: Оператор выбора выглядит следующим образом: Создадим новый скрипт, который будет выводить количество спутников для указанной планеты: Тест: Здесь в зависимости от введенного названия планеты скрипт выводит количество её спутников.В case мы использовали выражение Mercury | Venus, где | означает логическое "ИЛИ" (в отличие от if, где используется ||), чтобы выводить "no" для Меркурия и Венеры, не имеющих спутников. В case также можно указывать диапазоны с помощью . Например, скрипт для проверки принадлежности диапазону введенного символа будет выглядеть так: Мы проверяем символ на принадлежность одному из четырех диапазонов(английские символы в нижнем регистре, английские символы в верхнем регистре, цифры, все остальные символы). Результат теста: Цикл может задаваться тремя разными способами: Выполняется в интервале указанных значений (либо указанного множества): Выполняется, пока соблюдается условие: Выполняется, пока не начнёт соблюдаться условие: Добавим в скрипт с планетами цикл с условием while и будем выходить из скрипта, если вместо имени планеты будет введено EXIT Здесь мы также добавили условие, при котором оператор выбора будет выполняться только в случае, если введено не EXIT. Таким образом, мы будем запрашивать имя планеты и выводить количество её спутников до тех пор, пока не будет введено EXIT: Нужно отметить, что условие while [ $PLANET != "EXIT" ] можно заменить на until [ $PLANET == "EXIT" ]. == означает "равно", != означает "не равно". Приведем пример циклов с указанием интервалов и множеств: Сначала мы запрашиваем у пользователя количество файлов, которые необходимо сгенерировать (read count). В первом цикле (for (( i=1; i<=$count; i++ ))) мы генерируем несколько файлов, количество которых задано в переменной count, которую введет пользователь. В команду head передаем количество мегабайт, считываемых из устройства /dev/random, чтение из которого позволяет получать случайные байты. Символ < указывает перенаправление входного потока (/dev/urandom) для команды head. Символ > указывает перенаправление выходного потока (вывод команды head -c ${i}M ) в файл, имя которого мы генерируем на основе постоянной строки с добавлением в неё значения переменной цикла (myfile${i}mb.dat). Далее мы запрашиваем размер, файлы больше которого необходимо удалить. Во втором цикле (for f in *.dat) мы перебираем все файлы .dat в текущей директории и сравниваем размер каждого файла со значением, введенным пользователем. В случае, если размер файла больше, мы удаляем этот файл. В конце скрипта выводим список файлов .dat, чтобы отобразить список оставшихся файлов (ls -l *.dat). Результаты теста: Мы создали 10 файлов (myfile1mb.dat .. myfile10mb.dat) размером от 1 до 10 мегабайт и далее удалили все файлы .dat размером больше 5 мегабайт. При этом для каждого удаляемого файла вывели сообщение о его удалении (Deleted file myfile10mb.dat). В конце вывели список оставшихся файлов (myfile1mb.dat .. myfile5mb.dat). В следующей части мы рассмотрим функции, планировщик заданий cron, а также различные полезные команды. Разработчик ПО