Русский
Русский
English
Статистика
Реклама

Shells

Основы Bash-скриптинга для непрограммистов

24.01.2021 20:20:26 | Автор: admin

Статья рассчитана на тех, кто не имеет или имеет мало опыта работы с командной строкой Unix/Linux, но желает научиться с ней эффективно взаимодействовать и разрабатывать скрипты для выполнения своих задач. Приведенные примеры справедливы для выполнения в командной оболочке bash операционной системы Ubuntu/Debian, но могут быть использованы и в других оболочках и ОС с учетом их специфики.

1. Командные оболочки

Существует множество дистрибутивов(форков) операционных систем(ОС) семейства Linux, наиболее известные среди них: Ubuntu, Debian, CentOS, Red Hat, Fedora, SuSE, FreeBSD, Mint.

Здесь есть большая схема со всеми форками Linux.

В каждой ОС существуют различные командные оболочки (shell), их назначение одинаково (администрирование, автоматизация, вычисления, мониторинг и т.д.), как и большинство основных команд, но реализация может отличаться. В таблице ниже приведено сравнение, в котором видно, что некоторые возможности поддерживаются не всеми оболочками.

Feature

Bourne

C

TC

Korn

Bash

Псевдонимы (синонимы)

Нет

Да

Да

Да

Да

Редактор командной строки

Нет

Нет

Да

Да

Да

Расширенные шаблоны файлов

Нет

Нет

Нет

Да

Да

Автозавершение имени файла

Нет

Да

Да

Да

Да

Стеки директорий (pushd and popd)

Нет

Да

Да

Нет

Да

История

Нет

Да

Да

Да

Да

Функции

Да

Нет

Нет

Да

Да

Горячие клавиши

Нет

Нет

Да

Нет

Да

Управление заданиями

Нет

Да

Да

Да

Да

Исправление ошибок в командах

Нет

Нет

Да

Нет

Да

Формат приглашения командной строки

Нет

Нет

Да

Нет

Да

Список доступных командных оболочек можно получить командой

cat /etc/shells

При необходимости можно установить нужную командную оболочку командой sudo apt install <имя_оболочки>. Например, для установки ksh нужно выполнить

sudo apt install ksh

2. Настройка тестовой среды

Если у вас уже есть виртуальная/реальная машина с установленным Linux, или вы знаете, как её настроить, то можно пропустить информацию из спойлера ниже. Если есть доступ по ssh к какому-либо серверу, то Вы также можете использовать его shell для тренировок. Используйте имеющийся доступ с осторожностью, не тренируйтесь на продуктовых(промышленных) серверах и других критичных окружениях. Если вы не хотите развертывать виртуальную машину(ВМ), то для тестов можно воспользоваться онлайн-терминалами, но нужно знать и учитывать их особенности и ограничения. Примеры онлайн-терминалов:
https://cocalc.com/app?anonymous=terminal
https://www.tutorialspoint.com/execute_bash_online.php
https://rextester.com/l/bash_online_compiler

Развертывание виртуальной машины

VirtualBox ПО для виртуализации, позволяющее запускать одну ОС внутри другой. Разумеется, существуют и другие способы развертывания ВМ, здесь мы рассмотрим лишь один из них. В данном случае, предполагается, что у вас ПК под управлением Windows или Mac. Для начала нужно скачать VirtualBox отсюда и установить его.

Также нужно скачать образ ВМ с установленной ОС Ubuntu отсюда. Качайте самую новую версию, убедитесь, что скачиваемый образ имеет формат VirtualBox (VDI).

Создадим виртуальную машину. Сначала создаем на локальном диске папку для размещения в ней ВМ и их файлов (у меня C:\vmachines). Распакуем скачанный образ диска ВМ в созданную папку:

Для распаковки потребуется архиватор 7zip или другой, поддерживающий формат .7z. Далее запускаем VirtualBox и выбираем меню Машина -> Создать:

В открывшемся окне указываем имя ВМ (тип и версия в большинстве случаев подтягиваются автоматически, если это понятно из имени), а также созданную нами папку. Объем оперативной памяти устанавливается автоматически, 1Гб достаточно для выполнения тестов. Выбираем Использовать существующий виртуальный жесткий диск, нажимаем значок выбора образа жесткого диска, в открывшемся окне нажимаем Добавить, выбираем распакованный ранее файл образом ВМ и нажимаем Открыть:

Нажимаем Выбрать:

И нажимаем Создать:

Выбираем в списке созданную ВМ и нажимаем Запустить:

После запуска ВМ появится окно для входа в ОС:

Выбираем учетную запись osboxes.org и вводим пароль osboxes.org. После входа в систему нажимаем Ctrl+Alt+T, у нас откроется окно терминала, в котором можно выполнять тесты:

Для удобства можно развернуть окно виртуальной машины на весь экран, окно терминала также будет развернуто. Для того, чтобы можно было вставлять данные из буфера в терминал ВМ и копировать их, можно включить в настройках ВМ общий буфер обмена в меню Устройства -> Общий буфер обмена -> Двунаправленный:

Создадим тестового пользователя.

Для создания пользователя нам понадобятся права суперпользователя (root). Для их получения выполним команду sudo su -, указав пароль текущего пользователя (osboxes.org). Далее создадим пользователя test командой adduser test. Также выдадим пользователю test права на повышение привилегий при необходимости, выполнив команду usermod -aG sudo test:

osboxes@osboxes:~$ sudo su -[sudo] password for osboxes:root@osboxes:~# adduser testAdding user `test' ...Adding new group `test' (1001) ...Adding new user `test' (1001) with group `test' ...The home directory `/home/test' already exists.  Not copying from `/etc/skel'.New password:Retype new password:passwd: password updated successfullyChanging the user information for testEnter the new value, or press ENTER for the default        Full Name []:        Room Number []:        Work Phone []:        Home Phone []:        Other []:Is the information correct? [Y/n]root@osboxes:~# usermod -aG sudo testroot@osboxes:~#

На данном этапе уже можно использовать тестовую среду, выполняя команды в терминале (Ctrl+Alt+T). Дополнительно можно настроить подключение по ssh клиентом (например, PuTTY), мы рассмотрим это отдельно.

3. Первые команды

Итак, мы подключились к терминалу и находимся в shell. Давайте сориентируемся в пространстве.Чтобы узнать имя машины(сервера), на которой мы находимся, введем hostname и нажмем Enter:

test@osboxes:~$ hostnameosboxes

Имя пользователя, под которым мы подключены, как правило отображается в приглашении командной строки (test@osboxes:~$). Если имя текущего пользователя не отображается (например, если задан другой формат приглашения), то его можно получить командой whoami, или id (также отображает группы пользователя):

test@osboxes:~$ whoamitesttest@osboxes:~$ iduid=1001(test) gid=1001(test) groups=1001(test),27(sudo)

Чтобы узнать, в какой оболочке мы находимся, нужно выполнить команду echo $SHELL:

test@osboxes:~$ echo $SHELL/bin/bash

Разберем, что произошло. Команда echo выводит значение параметра, переданного ей, в нашем случае мы передали $SHELL. Знак $ означает, что мы обращаемся к переменной, т.е. $SHELL возвращает значение переменной SHELL, заданной в окружении. Список значений всех переменных можно получить командой env. Таким образом, отобразив значение переменной, мы видим, что мы находимся в оболочке bash. Оболочка конкретного пользователя указана в файле /etc/passwd, содержимое которого можно получить так:

test@osboxes:~$ cat /etc/passwdroot:x:0:0:root:/root:/bin/bash...test:x:1001:1001:,,,:/home/test:/bin/dash

Команда cat выводит содержимое файла (часть строк в приведенном выводе пропущена и заменена на ). Из файла видим, что для пользователя test указана оболочка /bin/dash. Изменить оболочку текущего пользователя, которая будет загружаться по умолчанию, можно следующей командой(chsh сокращенное от change shell):

test@osboxes:~$ chsh -s /bin/bashPassword:

Теперь давайте проверим, в каком каталоге мы находимся, для этого выполним команду pwd:

test@osboxes:~$ pwd/home/test

Для получения списка файлов текущей директории используем команду ls. По соглашению, скрытые файлы начинаются с точки. Для отображения их с помощью команды ls нужно добавить ключ a. Чтобы отобразить список в расширенном формате, добавим ключ l. Таким образом команда и её вывод будут выглядеть так:

test@osboxes:~$ ls -altotal 36drwxr-xr-x 5 test test 4096 Nov  9 01:05 .drwxr-xr-x 5 root root 4096 Nov  8 11:39 ..-rw------- 1 test test    9 Nov  8 12:28 .bash_history-rw-r--r-- 1 test test  220 Nov  8 11:39 .bash_logout-rw-r--r-- 1 test test 3771 Nov  8 11:39 .bashrcdrwxr-xr-x 4 test test 4096 Nov  8 11:40 .cachedrwxr-xr-x 4 test test 4096 Nov  8 11:40 .configdrwxr-xr-x 3 test test 4096 Nov  8 11:40 .local-rw-r--r-- 1 test test  807 Nov  8 11:39 .profile-rw-r--r-- 1 test test    0 Nov  9 01:05 .sudo_as_admin_successfultest@osboxes:~$

Для команды ls с параметрами может быть задан синоним (alias), что упрощает её ввод. Список уже заданных синонимов можно получить командой alias:

test@osboxes:~$ aliasalias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'alias egrep='egrep --color=auto'alias fgrep='fgrep --color=auto'alias grep='grep --color=auto'alias l='ls -CF'alias la='ls -A'alias ll='ls -alF'alias ls='ls --color=auto'

Видим, что команда ll является синонимом команды ls -alF. Синонимы могут ссылаться на другие синонимы. Так, в приведенном выше примере команда ll выполняет команду ls -alF, в которой ls в свою очередь также является синонимом команды ls --color=auto. Для любой команды с целью упрощения её ввода при частом использовании можно задать синоним. В синонимах также можно использовать переменные среды. Например, чтобы иметь возможность из любой директории получить список файлов домашней директории, можно задать синоним командой alias lshome='ls -alF $HOME', таким образом, можно выполнить:

test@osboxes:~$ cd /tmptest@osboxes:/tmp$ lshometotal 40drwxr-xr-x 5 test test 4096 Nov  9 02:29 ./drwxr-xr-x 5 root root 4096 Nov  8 11:39 ../-rw------- 1 test test   47 Nov  9 02:36 .bash_history-rw-r--r-- 1 test test  220 Nov  8 11:39 .bash_logout-rw-r--r-- 1 test test 3771 Nov  8 11:39 .bashrcdrwxr-xr-x 5 test test 4096 Nov  9 02:29 .cache/drwxr-xr-x 5 test test 4096 Nov  9 02:29 .config/drwxr-xr-x 3 test test 4096 Nov  8 11:40 .local/-rw-r--r-- 1 test test  807 Nov  8 11:39 .profile-rw-rw-r-- 1 test test   72 Nov  9 02:29 .selected_editor-rw-r--r-- 1 test test    0 Nov  9 01:05 .sudo_as_admin_successful

Здесь командой cd /tmp мы перешли в директорию /tmp, и, находясь в ней, выполнили команду lshome, которая вывела список файлов директории /home/test. При этом в синониме мы ссылаемся на переменную $HOME, в которой содержится путь к домашней директории текущего пользователя.

Алиасы задаются в файле ~/.bash_aliases. Тильда (~) означает домашнюю директорию пользователя. В нашем случае /home/test. Также можно задать их в файле ~/.bashrc. Здесь нужно сказать пару слов об этих файлах.

При запуске bash в качестве оболочки, сначала выполняется файлы (в случае их наличия), в которых могут быть заданы различные настройки профиля и выполнены различные действия в процессе входа до появления командной строки: сначала выполняется файл /etc/profile, далее bash последовательно ищет и выполняет первый из найденных файлов в следующем порядке: ~/.bash_profile, ~/.bash_login, ~/.profile. Из указанных файлов могут вызываться и другие.

Так, например, из файла ~./profile вызывается файл ~/.bashrc, из которого, в свою очередь, в числе прочих, вызывается файл .bash_aliases при его наличии. А файл /etc/profile выполняет также все файлы .sh, находящиеся в директории etc/profile.d.

В bash существуют внутренние команды, их список можно получить командой help. Помощь по конкретной внутренней команде можно получить с помощью команды help <имя_команды>, например:

test@osboxes:~$ help pwdpwd: pwd [-LP]    Print the name of the current working directory.    Options:      -L        print the value of $PWD if it names the current working                directory      -P        print the physical directory, without any symbolic links    By default, `pwd' behaves as if `-L' were specified.    Exit Status:    Returns 0 unless an invalid option is given or the current directory    cannot be read.

Некоторые внутренние команды bash дублированы в виде исполняемых файлов. Это сделано, чтобы скрипты можно было корректно выполнять в оболочках, в которых не реализованы эти команды. Например, существует исполняемый файл /usr/bin/echo, который реализует функционал внутренней команды echo. Команда help echo выведет справку по внутренней команде, а команда /usr/bin/echo help выведет справку для соответствующего исполняемого файла. Вывод справки для этих команд отличается, но в целом они реализуют идентичный функционал.

Таким образом, если в оболочке не реализована внутренняя команда echo, скрипт, содержащий вызов echo, сможет успешно выполниться, т.к. для обработки вызова будет использован исполняемый файл /usr/bin/echo. Для поиска выполненных ранее команд можно использовать клавиши Вверх и Вниз, команды из истории можно редактировать и повторно выполнять. В конце статьи приведен список полезных команд.

Если данный материал интересен, то в продолжении статьи я расскажу про скрипты и их параметры, права доступа к файлам, операторы условного выполнения, выбора и циклы, функции и планировщик заданий.

Подробнее..
Категории: *nix , Linux , Unix , Ubuntu , Bash , Bash scripting , Ssh , Virtualbox , Debian , Shells

Основы Bash-скриптинга для непрограммистов. Часть 2

30.01.2021 20:16:42 | Автор: admin

В первой части статьи мы рассмотрели командные оболочки, профили, синонимы и первые команды. Под спойлером я также рассказал, как развернуть тестовую виртуальную машину.

В этой части речь пойдет о файлах скриптов, их параметрах и правах доступа. Также я расскажу про операторы условного выполнения, выбора и циклы.

Скрипты

Для выполнения нескольких команд одним вызовом удобно использовать скрипты. Скрипт это текстовый файл, содержащий команды для shell. Это могут быть как внутренние команды shell, так и вызовы внешних исполняемых файлов.

Как правило, имя файла скрипта имеет окончание .sh, но это не является обязательным требованием и используется лишь для того, чтобы пользователю было удобнее ориентироваться по имени файла. Для интерпретатора более важным является содержимое файла, а также права доступа к нему.

Перейдем в домашнюю директорию командой cd ~ и создадим в ней с помощью редактора nano (nano script.sh)файл, содержащий 2 строки:

#!/bin/bashecho Hello!

Чтобы выйти из редактора nano после набора текста скрипта, нужно нажать Ctrl+X, далее на вопрос "Save modified buffer?" нажать Y, далее на запрос "File Name to Write:" нажать Enter. При желании можно использовать любой другой текстовый редактор.

Скрипт запускается командой ./<имя_файла>, т.е. ./ перед именем файла указывает на то, что нужно выполнить скрипт или исполняемый файл, находящийся в текущей директории. Если выполнить команду script.sh, то будет выдана ошибка, т.к. оболочка будет искать файл в директориях, указанных в переменной среды PATH, а также среди встроенных команд (таких, как, например, pwd):

test@osboxes:~$ script.shscript.sh: command not found

Ошибки не будет, если выполнять скрипт с указанием абсолютного пути, но данный подход является менее универсальным: /home/user/script.sh. Однако на данном этапе при попытке выполнить созданный файл будет выдана ошибка:

test@osboxes:~$ ./script.sh-bash: ./script.sh: Permission denied

Проверим права доступа к файлу:

test@osboxes:~$ ls -l script.sh-rw-rw-r-- 1 test test 22 Nov  9 05:27 script.sh

Из вывода команды ls видно, что отсутствуют права на выполнение. Рассмотрим подробнее на картинке:

Права доступа задаются тремя наборами: для пользователя, которому принадлежит файл; для группы, в которую входит пользователь; и для всех остальных. Здесь r, w и x означают соответственно доступ на чтение, запись и выполнение.

В нашем примере пользователь (test) имеет доступ на чтение и запись, группа также имеет доступ на чтение и запись, все остальные только на чтение. Эти права выданы в соответствии с правами, заданными по умолчанию, которые можно проверить командой umask -S. Изменить права по умолчанию можно, добавив вызов команды umask с нужными параметрами в файл профиля пользователя (файл ~/.profile), либо для всех пользователей в общесистемный профиль (файл /etc/profile).

Для того, чтобы установить права, используется команда chmod <параметры> <имя_файла>. Например, чтобы выдать права на выполнение файла всем пользователям, нужно выполнить команду:

test@osboxes:~$ chmod a+x script.sh

Чтобы выдать права на чтение и выполнение пользователю и группе:

test@osboxes:~$ chmod ug+rx script.sh

Чтобы запретить доступ на запись (изменение содержимого) файла всем:

test@osboxes:~$ chmod a-w script.sh

Также для указания прав можно использовать маску. Например, чтобы разрешить права на чтение, запись, выполнение пользователю, чтение и выполнение группе, и чтение для остальных, нужно выполнить:

test@osboxes:~$ chmod 754 script.sh

Будут выданы права -rwxr-xr--:

test@osboxes:~$ ls -la script.sh-rwxr-xr-- 1 test test 22 Nov  9 05:27 script.sh

Указывая 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)

Выдав права на выполнение, можно выполнить скрипт:

test@osboxes:~$ ./script.shHello!

Первая строка в скрипте содержит текст #!/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 следующего содержания:

#!/bin/bashecho Hello, $USER!printf "Specified City is: %s, Country is: %s\n" $1 $2

Выдадим права на выполнение и выполним скрипт с параметрами:

test@osboxes:~$ chmod u+x script1.shtest@osboxes:~$ ./script1.sh Moscow RussiaHello, test!Specified City is: Moscow, Country is: Russia

Мы передали 2 параметра, указывающие город и страну, и использовали их в скрипте, чтобы сформировать строку, выводимую командой printf. Также для вывода в строке Hello использовали имя пользователя из переменной USER.

Для того, чтобы передать значения параметров, состоящие из нескольких слов (содержащие пробелы), нужно заключить их в кавычки:

test@osboxes:~$ ./script1.sh "San Francisco" "United States"Hello, test!Specified City is: San Francisco, Country is: United States

При этом нужно доработать скрипт, чтобы в команду printf параметры также передавались в кавычках:

printf "Specified City is: %s, Country is: %s\n" "$1" "$2"

Из приведенных примеров видно, что при обращении к переменной для получения её значения используется символ $. Для того, чтобы сохранить значение переменной просто указывается её имя:

COUNTRY=RUSSIAecho $COUNTRY

Операторы условного выполнения, выбора и циклы

Так же, как и в языках программирования, в bash существуют операторы условного выполнения выполнение определенных действий при определенных условиях. Кроме того, существует возможность повторного выполнения определенного блока команд пока выполняется заданное условие операторы цикла. Рассмотрим каждый из них подробнее.

Оператор условного выполнения представляет собой конструкцию вида:

if [ <условие> ]then  <команда1>else  <команда2>fi

Создадим скрипт, проверяющий длину введенной строки (например, для проверки длины пароля), которая должна быть не меньше (т.е. больше) 8 символов:

#!/bin/bashecho Hello, $USER!echo -n "Enter string: "read strif [ ${#str} -lt 8 ]then  echo String is too shortelse  echo String is okfi

Выполним 2 теста, с длиной строки 5 и 8 символов:

test@osboxes:~$ ./script2.shHello, test!Enter string: abcdeString is too shorttest@osboxes:~$ ./script2.shHello, test!Enter string: abcdefghString is ok

Командой read str мы получаем значение, введенное пользователем и сохраняем его в переменную str. С помощью выражения ${#str} мы получаем длину строки в переменной str и сравниваем её с 8. Если длина строки меньше, чем 8 (-lt 8), то выдаем сообщение String is too short, иначе String is ok.

Условия можно комбинировать, например, чтобы указать, чтоб длина должна быть не меньше восьми 8 и не больше 16 символов, для условия некорректных строк нужно использовать выражение [ ${#str} -lt 8 ] || [ ${#str} -gt 16 ]. Здесь || означает логическое "ИЛИ", а для логического "И" в bash используется &&.

Условия также могут быть вложенными:

#!/bin/bashecho Hello, $USER!echo -n "Enter string: "read strif [ ${#str} -lt 8 ]then  echo String is too shortelse  if [ ${#str} -gt 16 ]  then    echo String is too long  else    echo String is ok  fifi

Здесь мы сначала проверяем, что строка меньше 8 символов, отсекая минимальные значения, и выводим "String is too short", если условие выполняется. Если условие не выполняется(строка не меньше 8 символов) - идем дальше(первый else) и проверяем, что строка больше 16 символов. Если условие выполняется - выводим "String is too long", если не выполняется(второй else) - выводим "String is ok".

Результат выполнения тестов:

test@osboxes:~$ ./script2.shHello, test!Enter string: abcdefString is too shorttest@osboxes:~$ ./script2.shHello, test!Enter string: abcdefghijklmnopqrstuvString is too longtest@osboxes:~$ ./script2.shHello, test!Enter string: abcdefghijklString is ok

Оператор выбора выглядит следующим образом:

case "$переменная" in "$значение1" ) <команда1>;; "$значение2" ) <команда2>;;esac

Создадим новый скрипт, который будет выводить количество спутников для указанной планеты:

#!/bin/bashecho -n "Enter the name of planet: "read PLANETecho -n "The $PLANET has "case $PLANET in  Mercury | Venus ) echo -n "no";;  Earth ) echo -n "one";;  Mars ) echo -n "two";;  Jupiter ) echo -n "79";;  *) echo -n "an unknown number of";;esacecho " satellite(s)."

Тест:

test@osboxes:~$ ./script3.shEnter the name of planet: MercuryThe Mercury has no satellite(s).test@osboxes:~$ ./script3.shEnter the name of planet: VenusThe Venus has no satellite(s).test@osboxes:~$ ./script3.shEnter the name of planet: EarthThe Earth has one satellite(s).test@osboxes:~$ ./script3.shEnter the name of planet: MarsThe Mars has two satellite(s).test@osboxes:~$ ./script3.shEnter the name of planet: JupiterThe Jupiter has 79 satellite(s).test@osboxes:~$ ./script3.shEnter the name of planet: Alpha555The Alpha555 has an unknown number of satellite(s).

Здесь в зависимости от введенного названия планеты скрипт выводит количество её спутников.
В case мы использовали выражение Mercury | Venus, где | означает логическое "ИЛИ" (в отличие от if, где используется ||), чтобы выводить "no" для Меркурия и Венеры, не имеющих спутников. В case также можно указывать диапазоны с помощью []. Например, скрипт для проверки принадлежности диапазону введенного символа будет выглядеть так:

#!/bin/bashecho -n "Enter key: "read -n 1 keyechocase "$key" in  [a-z]   ) echo "Lowercase";;  [A-Z]   ) echo "Uppercase";;  [0-9]   ) echo "Digit";;  *       ) echo "Something else";;esac

Мы проверяем символ на принадлежность одному из четырех диапазонов(английские символы в нижнем регистре, английские символы в верхнем регистре, цифры, все остальные символы). Результат теста:

test@osboxes:~$ ./a.shEnter key: tLowercasetest@osboxes:~$ ./a.shEnter key: PUppercasetest@osboxes:~$ ./a.shEnter key: 5Digittest@osboxes:~$ ./a.shEnter key: @Something else

Цикл может задаваться тремя разными способами:

Выполняется в интервале указанных значений (либо указанного множества):

for [ <условие> ] do <команды> done

Выполняется, пока соблюдается условие:

while [ <условие> ] do <команды> done

Выполняется, пока не перестанет соблюдаться условие:

until [ <условие> ] do <команды> done

Добавим в скрипт с планетами цикл с условием while и будем выходить из скрипта, если вместо имени планеты будет введено EXIT

#!/bin/bashPLANET="-"while [ $PLANET != "EXIT" ]do  echo -n "Enter the name of planet: "  read PLANET  if [ $PLANET != "EXIT" ]  then.    echo -n "The $PLANET has "    case $PLANET in      Mercury | Venus ) echo -n "no";;      Earth ) echo -n "one";;      Mars ) echo -n "two";;      Jupiter ) echo -n "79";;      *) echo -n "an unknown number of";;    esac  echo " satellite(s)."  fidone

Здесь мы также добавили условие, при котором оператор выбора будет выполняться только в случае, если введено не EXIT. Таким образом, мы будем запрашивать имя планеты и выводить количество её спутников до тех пор, пока не будет введено EXIT:

test@osboxes:~$ ./script4.shEnter the name of planet: EarthThe Earth has one satellite(s).Enter the name of planet: JupiterThe Jupiter has 79 satellite(s).Enter the name of planet: Planet123The Planet123 has an unknown number of satellite(s).Enter the name of planet: EXIT

Нужно отметить, что условие while [ $PLANET != "EXIT" ] можно заменить на until [ $PLANET == "EXIT" ]. == означает "равно", != означает "не равно".

Приведем пример циклов с указанием интервалов и множеств:

#!/bin/bashrm *.datecho -n "File count: "read countfor (( i=1; i<=$count; i++ ))do  head -c ${i}M </dev/urandom >myfile${i}mb.datdonels -l *.datecho -n "Delete file greater than (mb): "read maxsizefor f in *.datdo  size=$(( $(stat -c %s $f) /1024/1024))  if [ $size -gt $maxsize ]  then.    rm $f    echo Deleted file $f  fidonels -l *.datread

Сначала мы запрашиваем у пользователя количество файлов, которые необходимо сгенерировать (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). Результаты теста:

test@osboxes:~$ ./script5.shFile count: 10-rw-rw-r-- 1 test test 10485760 Nov  9 08:48 myfile10mb.dat-rw-rw-r-- 1 test test  1048576 Nov  9 08:48 myfile1mb.dat-rw-rw-r-- 1 test test  2097152 Nov  9 08:48 myfile2mb.dat-rw-rw-r-- 1 test test  3145728 Nov  9 08:48 myfile3mb.dat-rw-rw-r-- 1 test test  4194304 Nov  9 08:48 myfile4mb.dat-rw-rw-r-- 1 test test  5242880 Nov  9 08:48 myfile5mb.dat-rw-rw-r-- 1 test test  6291456 Nov  9 08:48 myfile6mb.dat-rw-rw-r-- 1 test test  7340032 Nov  9 08:48 myfile7mb.dat-rw-rw-r-- 1 test test  8388608 Nov  9 08:48 myfile8mb.dat-rw-rw-r-- 1 test test  9437184 Nov  9 08:48 myfile9mb.datDelete file greater than (mb): 5Deleted file myfile10mb.datDeleted file myfile6mb.datDeleted file myfile7mb.datDeleted file myfile8mb.datDeleted file myfile9mb.dat-rw-rw-r-- 1 test test 1048576 Nov  9 08:48 myfile1mb.dat-rw-rw-r-- 1 test test 2097152 Nov  9 08:48 myfile2mb.dat-rw-rw-r-- 1 test test 3145728 Nov  9 08:48 myfile3mb.dat-rw-rw-r-- 1 test test 4194304 Nov  9 08:48 myfile4mb.dat-rw-rw-r-- 1 test test 5242880 Nov  9 08:48 myfile5mb.dat

Мы создали 10 файлов (myfile1mb.dat .. myfile10mb.dat) размером от 1 до 10 мегабайт и далее удалили все файлы .dat размером больше 5 мегабайт. При этом для каждого удаляемого файла вывели сообщение о его удалении (Deleted file myfile10mb.dat). В конце вывели список оставшихся файлов (myfile1mb.dat .. myfile5mb.dat).

В следующей части мы рассмотрим функции, планировщик заданий cron, а также различные полезные команды.

Подробнее..
Категории: *nix , Linux , Unix , Ubuntu , Bash , Bash scripting , Ssh , Virtualbox , Debian , Shells

Основы Bash-скриптинга для непрограммистов. Часть 3

16.02.2021 20:15:11 | Автор: admin

Во второй части статьи мы обсудили файлы скриптов, их параметры и права доступа. Также поговорили про операторы условного выполнения, выбора и циклы. В этой, заключительной части мы рассмотрим функции и планировщик заданий 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 является очень гибким инструментом, позволяющим реализовать задачи различного уровня сложности. При подключении внешних утилит предоставляет большие возможности для автоматизации.

На этом пока все, надеюсь, было интересно!
Какие другие полезные команды вы знаете и используете в работе?
Какие интересные конструкции приходилось использовать?
Какие задачи решали?
Всем удачного скриптинга, делитесь мнениями в комментариях!

Подробнее..
Категории: *nix , Linux , Unix , Ubuntu , Bash , Bash scripting , Ssh , Virtualbox , Debian , Shells

Категории

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

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru