Во второй части статьи мы обсудили файлы скриптов, их параметры и права доступа. Также поговорили про операторы условного выполнения, выбора и циклы. В этой, заключительной части мы рассмотрим функции и планировщик заданий cron. Также приведу различные полезные команды и ссылки.
Функции
Часто используемые, повторяющиеся блоки имеет смысл выделять в отдельные функции, чтобы при необходимости их запускать, передавая параметры.
Определение функции выглядит следующим образом:
<имя_функции>() { <команды> return <число>}funciton <имя_функции>() { <команды> return <число>}
Первый вариант ближе к синтаксису языка С и считается более переносимым, во втором варианте круглые скобки можно не указывать. Также может отсутствовать оператор return, если функция не возвращает значения.
Самый простой пример скрипта, содержащего объявление и вызов функции будет выглядеть так:
#!/bin/bashf() { echo Test}f
Мы объявили функцию f
, которая выводит слово Test,
и затем вызвали её:
test@osboxes:~$ ./script6.shTest
Так же, как и скрипт, функция может принимать параметры и использовать их, ссылаясь по номеру ($1, $2, , $N). Вызов функции с параметрами в скрипте осуществляется так:
<имя функции> <параметр1> <параметр2> <параметрN>
Функция может возвращать результат своего выполнения (код
завершения) в виде числового значения в диапазоне от 0 до 255.
Принято считать, что если функция возвращает 0, то она выполнилась
успешно, во всех остальных случаях значение содержит код ошибки.
Чтобы получить код завершения функции в скрипте, необходимо
обратиться к переменной $?
. Добавив параметры и
возвращаемое значение, получим следующий скрипт:
#!/bin/bashsumm() { re='^[0-9]+$' if ! [[ $1 =~ $re ]] ; then return 1 elif ! [[ $2 =~ $re ]] ; then return 2 else s=$(($1 + $2)) return 0 fi}summ $1 $2case $? in 0) echo "The sum is: $s" ;; 1) echo "var1 is not a nubmer" ;; 2) echo "var2 is not a nubmer" ;; *) echo "Unknown error" ;;esac
Здесь мы создали функцию summ, которая принимает 2 параметра и с
помощью регулярного выражения ^[0-9]+$
проверяет,
является ли каждый из переданных параметров числом. В случае, если
первый параметр не число, то код завершения функции будет 1, если
второй параметр не число, то код завершения функции будет 2. Во
всех остальных случаях функция вычисляет сумму переданных
параметров, сохраняя результат в глобальной переменной s.
Скрипт вызывает функцию, передавая её на вход параметры, которые
были переданы ему самому при вызове. Далее проверяется код
завершения функции и выдается соответствующая ошибка, если код не
равен 0, иначе выдается сумма, сохраненная в переменной
s
. Протестируем скрипт:
test@osboxes.org:~$ ./script7.sh abc 123var1 is not a nubmertest@osboxes.org:~$ ./script7.sh 234 defvar2 is not a nubmertest@osboxes.org:~$ ./script7.sh 10 15The sum is: 25
По умолчанию переменные объявляются глобальными, т.е. видны в любом блоке скрипта. Переменные, объявленные как локальные, имеют ограниченную область видимости, и видны только в пределах блока, в котором они были объявлены. В случае с функцией это означает, что локальная переменная "видна" только в теле функции, в которой она была объявлена.
Для того, чтобы объявить переменную локальной, используется
слово local, например local loc_var=123
. Важно
отметить, все что переменные, объявляемые в теле функции, считаются
необъявленными до тех пор, пока эта функция не будет вызвана.
Объединим все воедино, создав на основе рассмотренных ранее структур следующий скрипт:
#!/bin/bashclearFiles() { rm *.dat if [ $? -eq 0 ] then echo Files deleted fi}genFiles() { for (( i=1; i<=$1; i++ )) do head -c ${i}M </dev/urandom >myfile${i}mb.dat done ls -l *.dat}delFiles() {for f in *.dat do size=$(( $(stat -c %s $f) /1024/1024 )) if [ $size -gt $1 ] then rm $f echo Deleted file $f fi done ls -l *.dat}showWeather() { curl -s "https://weather-broker-cdn.api.bbci.co.uk/en/observation/rss/$1" | grep "<desc" | sed -r 's/<description>//g; s/<\/description>//g'}menu() { clear echo 1 - Delete all .dat files echo 2 - Generate .dat files echo 3 - Delete big .dat files echo 4 - List all files echo 5 - Planet info echo 6 - Show weather echo "x/q - Exit" echo -n "Choose action: " read -n 1 key echo}while truedo case "$key" in "x" | "q" | "X" | "Q") break ;; "1") clearFiles read -n 1 ;; "2") echo -n "File count: " read count genFiles $count read -n 1 ;; "3") echo -n "Delete file greater than (mb): " read maxsize delFiles $maxsize read -n 1 ;; "4") ls -la read -n 1 ;; "5") ./script4.sh read -n 1 ;; "6") echo -n "Enter city code: " # 524901 498817 5391959 read citycode showWeather $citycode read -n 1 ;; esac menudone
В данном скрипте мы объявили 5 функций:
-
clearFiles
-
genFiles
-
delFiles
-
showWeather
-
menu
Далее реализован бесконечный цикл с помощью оператора while с условием true, в который вложен оператор выбора в зависимости от нажатой клавиши, а также вызов функции menu для отображения списка доступных действий. Данный скрипт в интерактивном режиме позволяет выполнить следующие действия:
-
Удалить все файлы .dat в текущей директории
-
Создать указанное количество файлов
-
Удалить файлы больше определенного размера
-
Вывести список всех файлов текущей директории
-
Запустить скрипт, выдающий информацию о планетах
-
Отобразить погоду по коду указанного города
Не будем подробно разбирать все строки кода, скажем только, что в скрипте демонстрируется вызов другого скрипта, получение информации из интернет, и её парсинг (выделение нужной информации), команда break для выхода из цикла и ряд других возможностей. Предлагаю желающим самостоятельно протестировать скрипт, посмотреть, какие могут быть ошибки при его работе и при вводе различных значений, какие проверки можно добавить, и что можно улучшить. Приведем результаты тестирования:
test@osboxes.org:~$ ./script8.sh1 - Delete all .dat files2 - Generate .dat files3 - Delete big .dat files4 - List all files5 - Planet info6 - Show weatherx/q - ExitChoose action: 4total 40drwxr-xr-x 2 test test 4096 Feb 16 15:56 .drwxr-xr-x 6 root root 4096 Feb 16 15:54 ..-rw------- 1 test test 42 Feb 16 15:55 .bash_history-rw-r--r-- 1 test test 220 Feb 16 15:54 .bash_logout-rw-r--r-- 1 test test 3771 Feb 16 15:54 .bashrc-rw-r--r-- 1 test test 807 Feb 16 15:54 .profile-rw-r--r-- 1 test test 1654 Feb 16 12:40 input.xml-rwxr-xr-x 1 test test 281 Feb 16 14:02 script4.sh-rwxr-xr-x 1 test test 328 Feb 16 13:40 script7.sh-rwxr-xr-x 1 test test 1410 Feb 16 15:24 script8.sh
1 - Delete all .dat files2 - Generate .dat files3 - Delete big .dat files4 - List all files5 - Planet info6 - Show weatherx/q - ExitChoose action: 2File count: 8-rw-rw-r-- 1 test test 1048576 Feb 16 16:00 myfile1mb.dat-rw-rw-r-- 1 test test 2097152 Feb 16 16:00 myfile2mb.dat-rw-rw-r-- 1 test test 3145728 Feb 16 16:00 myfile3mb.dat-rw-rw-r-- 1 test test 4194304 Feb 16 16:00 myfile4mb.dat-rw-rw-r-- 1 test test 5242880 Feb 16 16:00 myfile5mb.dat-rw-rw-r-- 1 test test 6291456 Feb 16 16:00 myfile6mb.dat-rw-rw-r-- 1 test test 7340032 Feb 16 16:00 myfile7mb.dat-rw-rw-r-- 1 test test 8388608 Feb 16 16:00 myfile8mb.dat
1 - Delete all .dat files2 - Generate .dat files3 - Delete big .dat files4 - List all files5 - Planet info6 - Show weatherx/q - ExitChoose action: 3Delete file greater than (mb): 5Deleted file myfile6mb.datDeleted file myfile7mb.datDeleted file myfile8mb.dat-rw-rw-r-- 1 test test 1048576 Feb 16 16:00 myfile1mb.dat-rw-rw-r-- 1 test test 2097152 Feb 16 16:00 myfile2mb.dat-rw-rw-r-- 1 test test 3145728 Feb 16 16:00 myfile3mb.dat-rw-rw-r-- 1 test test 4194304 Feb 16 16:00 myfile4mb.dat-rw-rw-r-- 1 test test 5242880 Feb 16 16:00 myfile5mb.dat
1 - Delete all .dat files2 - Generate .dat files3 - Delete big .dat files4 - List all files5 - Planet info6 - Show weatherx/q - ExitChoose action: 1Files deleted
1 - Delete all .dat files2 - Generate .dat files3 - Delete big .dat files4 - List all files5 - Planet info6 - Show weatherx/q - ExitChoose action: 5Enter the name of planet: MarsThe Mars has two satellite(s).
1 - Delete all .dat files2 - Generate .dat files3 - Delete big .dat files4 - List all files5 - Planet info6 - Show weatherx/q - ExitChoose action: 6Enter city code: 524901 Latest observations for Moscow from BBC Weather, including weather, temperature and wind information Temperature: -11C (11F), Wind Direction: Northerly, Wind Speed: 0mph, Humidity: 84%, Pressure: 1018mb, , Visibility: Moderate
Примечание: для тестирования работы с данными из Интернет (пункт
6 в меню выбора скрипта) может потребоваться установка curl, это
можно сделать командой sudo apt install curl
.
Планировщик заданий cron
В случае, когда есть необходимость периодического запуска скриптов, полезно использовать планировщик cron, он позволяет задать расписание запуска скрипта и не требует присутствия администратора.
Просмотр заданий пользователя выполняется командой crontab
l
. Для редактирования и создания новых задания используется
команда crontab e
. Строки для запуска команд
планировщика в файле конфигурации cron имеют следующий формат:
m h dom mon dow command parameters
Где m минута, h час, dom день месяца, mon месяц, dow день недели, command команда, parameters список параметров. Наглядно этот формат можно представить так:
Например, для того, чтобы в 10 и 30 минут каждого часа каждый день месяца весь год по будням запускать команду, нужно указать следующее:
10,30 * * * 1-5 command parameter1 parameter2
Более простой пример, каждые 15 минут выполнять команду:
*/15 * * * * command
Создадим скрипт для резервного копирования домашней директории пользователя, который будет создавать новый файл бэкапа при каждом запуске:
#!/bin/bashUSER=`whoami`BACKUP_DIR=/tmp/backup_${USER}BACKUP_FILE=${USER}_$(date +%Y%m%d%M%H%S).tgzmkdir -p $BACKUP_DIRcd /tar -zcf $BACKUP_DIR/$BACKUP_FILE home/$USER
Поставим скрипт на выполнение каждый день в 22:00, выполнив
команду crontab -e
и добавив с помощью открывшегося
редактора строку:
00 22 * * * ./backup_home.sh
Проверить, что задача добавлена в планировщик, можно командой
crontab -l
:
test@osboxes.org:~$ crontab -l00 22 * * * ./backup_home.sh
В результате каждый день в 22:00 будет создаваться резервная копия домашней директории пользователя (в приведенном примере для демонстрации запуск скрипта выполняется каждую минуту):
test@osboxes.org:~$ cd /tmp/backup_test/test@osboxes:/tmp/backup_test$ lltotal 80drwxrwxr-x 2 test test 4096 Feb 16 16:38 ./drwxrwxrwt 17 root root 4096 Feb 16 16:30 ../-rw-rw-r-- 1 test test 4431 Feb 16 16:30 test_20210216301601.tgz-rw-rw-r-- 1 test test 4431 Feb 16 16:31 test_20210216311601.tgz-rw-rw-r-- 1 test test 4431 Feb 16 16:32 test_20210216321601.tgz-rw-rw-r-- 1 test test 4431 Feb 16 16:33 test_20210216331601.tgz-rw-rw-r-- 1 test test 4431 Feb 16 16:34 test_20210216341601.tgztest@osboxes:/tmp/backup_test$
Нужно отметить, что директория /tmp в примере использована исключительно для тестов, т.к. она предназначена для хранения временных файлов, и использовать её для хранения резервных копий нельзя. Правильное место размещения бэкапов может подсказать системный администратор.
Список полезных команд
Список встроенных команд интерпретатора: help
Помощь по команде: <команда> --help
Мануал по команде: man <команда>
Версия команды: <команда> --version
Список доступных оболочек: cat /etc/shells
Список пользователей и их оболочек: cat /etc/passwd
Текущая директория: pwd
Список файлов текущей директории: ls -la
Текущий пользователь: id
Переменные среды: set
Версия ОС: cat /etc/os-release
Версия ядра: uname -a
Получить привилегии суперпользователя: sudo su -
Установка программы в Debian: apt install mc
Посмотреть утилизацию(загрузку): top
Свободное место: df -h
Сколько занимает директория: du -ks /var/log
Конфигурация сетевых интерфейсов: ifconfig -a
Объем оперативной памяти: free -m
Информация о блочных устройствах(дисках): lsblk
Информация о процессорах: cat /proc/cpuinfo
Список установленных пакетов: apt list --installed
Список и статус сервисов: service --status-all
Перезапуск сервиса: service apache2 restart
Скачать файл: wget
https://www.gnu.org/graphics/gplv3-with-text-136x68.png
Получить веб-страницу по URL: curl https://www.google.com
Показать задания планировщика: crontab -l
Редактировать задания планировщика: crontab -e
Вывести новые сообщения в системном логе: tail -f
/var/log/syslog
Подсчитать количество строк в выводе команды: <команда> | wc
-l
Изменить права доступа к файлу (разрешить выполнение всем): chmod
a+x <файл>
Список процессов: ps -ef
Проверить, запущен ли процесс: ps -ef | grep <процесс>
Перейти в предыдущий каталог: cd -
Завершить процесс (сигнал kill): kill -9
Удаление файла: rm <имя файла>
Удаление директории: rm -rf <имя директории>
Редактировать файл: nano <имя_файла>
Топ 10 процессов по использованию памяти: ps aux | awk '{print
$6/1024 " MB\t\t" $11}' | sort -nr | head
Полезные ссылки
Руководство по bash: GNU Bash manual
Расширенное руководство по Bash: Advanced Bash-Scripting
Guide
Статья на Википедии: Bash
Описание команд и утилит оболочки bash: SS64
Часто задаваемые вопросы о Debian GNU/Linux: Debian FAQ
Заключение
В данной статье мы рассмотрели основы разработки скриптов с использованием bash, изучили базовые структуры, позволяющие реализовывать логику работы скрипта в зависимости от различных условий, познакомились с планировщиком. Bash является очень гибким инструментом, позволяющим реализовать задачи различного уровня сложности. При подключении внешних утилит предоставляет большие возможности для автоматизации.
На этом пока все, надеюсь, было интересно!
Какие другие полезные команды вы знаете и используете в работе?
Какие интересные конструкции приходилось использовать?
Какие задачи решали?
Всем удачного скриптинга, делитесь мнениями в комментариях!