Скрипты в Linux
Скрипт или как его еще называют сценарий, это последовательность команд которые по очереди считывает и выполняет программа-интерпретатор, в нашем случае это программа командной строки bash
.
Скрипт - это текстовый файл в котором перечислены обычные команды, которые мы привыкли вводить вручную, а также указанна программа которая будет их выполнять. Загрузчик, который будет выполнять скрипт не умеет работать с переменными окружения, поэтому ему нужно передать точный путь к программе которую нужно запустить. А дальше он уже передаст ваш скрипт этой программе и начнется выполнение.
Простейший пример скрипта для командной оболочки Bash:
#!/bin/bash
echo "Hello world"
Утилита echo
выводит строку, переданную ей в параметре на экран. Первая строка особая, она задает программу которая будет выполнять команды. Мы можем создать скрипт на любом другом языке программирования и указать нужный интерпретатор, например на python:
#!/usr/bin/env python
print("Hello world")
Или на PHP:
#!/usr/bin/env php
echo "Hello world";
В первом случае мы прямо указали на программу, которая будет выполнять команды, в двух следующих мы не знаем точный адрес программы, поэтому просим утилиту env найти ее по имени и запустить. Такой подход используется во многих скриптах. В системе Linux, чтобы система могла выполнить скрипт, нужно установить на файл с ним флаг исполняемый.
Флаг ничего не меняет в самом файле, только говорит системе что это не просто текстовый файл, а программа и ее нужно выполнять:
- Открыть файл
- Узнать интерпретатор
- Выполнить
Сначала давайте создадим файл сценария bash
в редакторе nano
:
nano test.sh
Затем напишем текст и сохранили файл, как показано ниже:
#!/bin/bash
echo "Тест пройден"
Сделаем файл исполняемым:
chmod ugo+x test.sh
Проверим является ли файл исполняемым или нет:
ls -l test.sh
Выполним файл:
./test.sh
Все работает. Вы уже знаете как написать маленький скрипт, скажем для обновления. Как видите, скрипты содержат те же команды, что и выполняются в терминале, их писать очень просто. Но теперь мы немного усложним задачу. Поскольку скрипт, это программа, ему нужно самому принимать некоторые решения, хранить результаты выполнения команд и выполнять циклы. Все это позволяет делать оболочка Bash.
Переменные в скриптах
Написание скриптов на Bash редко обходится без сохранения временных данных таких как строки и числа, а значит создания переменных. Без переменных не обходится ни один язык программирования и наш примитивный язык командной оболочки тоже. Переменные могут быть определены явно, путем присвоения значения, или неявно, путем автоматического присвоения значения при выполнении определенных операций
Объявим переменную string
, для создания переменной в Bash необходимо присвоить ей значение, используя знак равенства =
:
string="Hello world"
Пробел это специальный символ разделитель, поэтому если не использовать кавычки слово world
уже будет считаться отдельной командой, по той же причине мы не ставим пробелов перед и после знака равно.
Чтобы вывести значение переменной используется символ $
:
echo $string
Модифицируем наш скрипт:
#!/bin/bash
string1="hello "
string2=world
string3=$string1$string2
echo $string3
И проверяем:
./test.sh
В переменные можно записать данные и результат выполнения утилит. Для этого используется такой синтаксис:
$(команда)
С помощью этой конструкции вывод команды будет перенаправлен прямо туда, откуда она была вызвана а не на экран. Утилита date
возвращает текущую дату, эти команды эквивалентны:
date
echo $(date)
Напишем скрипт, где будет выводиться hello world и дата
:
#!/bin/bash
string1="hello world "
string2=$(date)
string=$string1$string2
echo $string
Также возможно присвоить значение переменной через ввод с клавиатуры с помощью команды read
. Например, следующий скрипт запрашивает у пользователя имя и сохраняет его в переменной:
#!/bin/bash
echo "What is your name?"
read name
echo "Hello, $name!"
Переменные также могут использоваться для передачи значений между различными командами и скриптами. Например, для передачи значения переменной из одного скрипта в другой, необходимо использовать команду export
:
export название_переменной
Параметры скрипта
Не всегда можно создать bash
скрипт который не зависит от ввода пользователя. В большинстве случаев нужно спросить у пользователя какое действие предпринять или какой файл использовать. При вызове скрипта мы можем передавать ему параметры, параметры доступны в виде переменных с именами в виде номеров.
Переменная с именем $1
содержит значение первого параметра, переменная с именем $2
содержит значение второго и так далее. Этот bash
скрипт выведет значение первого параметра:
#!/bin/bash
echo $1
Внутри скрипта, возможно использовать специальные параметры командной строки:
$0
имя скрипта (то есть, имя файла, который был запущен)$#
количество переданных параметров$*
или$@
список всех переданных параметров (в виде одной строки или массива соответственно)$?
код возврата последней выполненной команды
Конструкции if else
Создание bash
скрипта было бы не настолько полезным без возможности анализировать определенные факторы и выполнять в ответ на них нужные действия.
Для проверки условий есть команда синтаксис ее такой:
if [ команда_условие ] then команда_которую_выполняем else команда fi
Команда проверяет код завершения команды условия, если 0
(успех) выполняет команду или несколько команд после слова then
, если код завершения 1
выполняется блок else
, параметр fi
означает завершение блока команд.
Поскольку чаще всего нас интересует не код возврата команды, а сравнение строк и чисел, была введена команда [[
, которая позволяет выполнять различные сравнения и выдавать код возврата зависящий от результата сравнения:
[[ параметр1 оператор параметр2 ]]
Для сравнения используются уже привычные нам операторы. Если выражение верно, команда вернет 0
, если нет 1
.
#!/bin/bash
if [[ $1 > 2 ]]
then
echo $1" больше 2"
else
echo $1" меньше 2 или 2"
fi
С помощью оператора elif
можно проверять дополнительные условия и определять команды, котоорые выполняются при истинности этих условий. Этот оператор во многом аналогичен if
:
#!/bin/bash
if [ "$a" = "$b" ]
then
echo 'true'
elif [[ "$a" =~ $b ]]
then
echo 'true'
else
echo 'false'
fi
Написать if
можно в одну строку:
if [ $x -ne 0 ]; then echo 1; fi
if [ $x -ne 0 -a $y -eq 1 ]; then echo 1; else echo 2; fi
Можно обойтись без if
:
[[ $? -ne 0 ]] && echo 1 || echo 2
Конструкция Case
Конструкция case
позволяет упростить написание условных операторов для сравнения переменных с несколькими возможными значениями.
Синтаксис конструкции case выглядит следующим образом:
#!/bin/bash
case variable in
pattern1)
command1
;;
pattern2)
command2
;;
pattern3)
command3
;;
*)
default command
;;
esac
variable
переменная, которую нужно проверитьpattern1, pattern2, pattern3
возможные значения, которые нужно проверитьcommand1, command2, command3
команды, которые нужно выполнить в зависимости от значения переменной- Символ
*
в конце списка значений используется как обработчик по умолчанию, если ни одно из значений не соответствует переменной
Для примера, давайте рассмотрим скрипт, который проверяет день недели и выполняет соответствующее действие:
#!/bin/bash
day=$(date +%u)
case $day in
1)
echo "Сегодня понедельник"
;;
2)
echo "Сегодня вторник"
;;
3)
echo "Сегодня среда"
;;
4)
echo "Сегодня четверг"
;;
5)
echo "Сегодня пятница"
;;
6)
echo "Сегодня суббота"
;;
7)
echo "Сегодня воскресенье"
;;
*)
echo "Некорректное значение дня недели"
;;
esac
В этом примере мы используем переменную day
, которую мы определяем с помощью команды date +%u
. В данном случае, %u
используется для получения числового значения дня недели от 1 (понедельник) до 7 (воскресенье). Затем мы сравниваем эту переменную с днями недели, используя конструкцию case
. Если ее значение соответствует определенному значению дня недели, то мы выводим соответствующее сообщение. Если значение не соответствует перечисленным дням недели, мы выводим сообщение об ошибке.
Циклы
Преимущество программ в том, что мы можем в несколько строчек указать какие действия нужно выполнить несколько раз. Возможно написание скриптов на bash
, которые состоят всего из нескольких строчек, а выполняются часами анализируя параметры и выполняя нужные действия.
Первым рассмотрим цикл for
, используется для выполнения команд для каждого элемента из списка:
for переменная in список do команда done
Перебирает весь список и присваивает по очереди переменной значение из списка, после каждого присваивания выполняет команды расположенные между do
и done
.
Переберем пять цифр:
#!/bin/bash
for index in 1 2 3 4 5
do
echo $index
done
Вторым рассмотрим цикл while
, он выполняется пока команда условия возвращает код 0
(успех):
while [ условие ] do команда done
Здесь в квадратных скобках указывается условие, которое проверяется перед каждой итерацией цикла. Команды, указанные между do
и done
, будут выполнены до тех пор, пока условие остается истинным.
#!/bin/bash
count=1
while [ $count -le 5 ]; do
echo "Count: $count"
count=$((count+1))
done
В этом примере count
увеличивается на 1
после каждой итерации цикла. Когда значение count
достигает 4
, цикл завершается.
Функции
Функции используются для группировки команд в логически связанные блоки. Функции могут быть вызваны из скрипта с помощью имени функции.
Синтаксис функции выглядит следующим образом:
название_функции () {
команды_и_выражения
}
Название функции должно начинаться с буквы или символа подчеркивания и может содержать только буквы, цифры и символы подчеркивания. За названием функции следует список аргументов в скобках. Команды и выражения, которые должны быть выполнены при вызове функции, должны быть внутри фигурных скобок.
Пример функции, которая выводит текущее время и дату:
#!/bin/bash
print_date () {
echo "Сегодняшняя дата: $(date)"
}
#вызов функции
print_date
Функции также могут иметь аргументы, которые передаются в качестве параметров внутри скобок при их вызове. Вот пример функции, которая принимает два аргумента и выводит их сумму:
#!/bin/bash
sum_numbers () {
result=$(( $1 + $2 ))
echo "Сумма чисел $1 и $2 равна $result"
}
#вызов функции
sum_numbers 10 20
В этом примере $1
и $2
переменные, которые содержат значения первого и второго аргументов соответственно. sum_numbers 10 20
вызовет функцию sum_numbers
.
Функции также могут возвращать значения при помощи ключевого слова return
. Перепишем прошлый пример, используя новые знания:
#!/bin/bash
sum_numbers () {
result=$(( $1 + $2 ))
return $result
}
#вызов функции
sum_numbers 12 24
#вывод
echo "Сумма чисел равна $?"
Здесь результат сохраняется в переменную result
и возвращается из функции с помощью команды return
.
Переменная $?
содержит код возврата функции, то есть в данном случае — результат вычисления суммы.
Есть и другой способ взаимодействия с результатом вызова функции, помимо return
. Немного перепишем код прошлого скрипта:
#!/bin/bash
sum_numbers () {
result=$(( $1 + $2 ))
echo $result
}
sum=$(sum_numbers 9 11)
#вывод
echo "Сумма чисел равна $sum"
Здесь, вместо использования $?
и return
, мы сохраняем результат вызова функции в переменную sum
и затем выводим ее значение на экран.