Написание скриптов на Bash. Функции bash в скриптах Что такое bash скрипт

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

В сегодняшней статье мы исправим этот недостаток. Как и в любом языке программирования, в Bash есть функции их может быть очень полезно использовать. Мы рассмотрим использование функций bash, как их писать и даже как создавать библиотеки из этих функций.

Сначала нужно понять что такое функция в нашем контексте. Функция - это набор команд, объединенных одним именем, которые выполняют определенную задачу. Функция вызывается по ее имени, может принимать параметры и возвращать результат работы. Одним словом, функции Bash работают так же, как и в других языках программирования.

Синтаксис создания функции очень прост:

имя_функции () { список_команд }

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

Простая функция

Давайте напишем небольшую функцию, которая будет выводить строку на экран:

$ vi function.sh

#!/bin/bash
printstr(){
echo "hello world"
}
printstr

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

chmod u+x function.sh

Все работает, теперь усложним задачу, попробуем передать функции аргументы.

Аргументы функции

Аргументы функции нужно передавать при вызове, а читаются они точно так же, как и аргументы скрипта. Синтаксис вызова функции с параметрами bash такой:

имя_функции аргумент1 аргумент2 ... аргументN

Как видите, все достаточно просто. Параметры разделяются пробелом. Теперь улучшим нашу функцию, чтобы она выводила заданную нами строку:

!/bin/bash
printstr(){
echo $1
}
printstr "Hello world"

Можно сделать, чтобы параметров было несколько:

!/bin/bash
printstr(){
echo $1
echo $2
echo $3
echo $5
}
printstr "arg1" "arg2" "arg3" "arg4" "arg5"

Есть и другой способ извлекать аргументы, как в Си, с помощью стека. Мы извлекаем первый аргумент, затем сдвигаем указатель стека аргументов на единицу и снова извлекаем первый аргумент. И так далее:

!/bin/bash
printstr(){
echo $1
shift
echo $1
shift
echo $1
shift
echo $1
}
printstr "arg1" "arg2" "arg3" "arg4"

Возврат результата функции

Вы можете не только использовать функции с параметрами bash, но и получить от нее результат работы. Для этого используется команда return. Она завершает функцию и возвращает числовое значение кода возврата. Он может быть от 0 до 255:

!/bin/bash
printstr(){
return 134;
}
printstr
echo $?

Если вам нужно применить возврат значения функции bash, а не статус код, используйте echo. Строка не сразу выводится в терминал, а возвращается в качестве результата функции и ее можно записать в переменную, а затем использовать:

!/bin/bash
printstr(){
echo "test"
}
VAR=$(printstr)
echo $VAR

Экспорт функций

Вы можете сделать функцию доступной вне скрипта с помощью команды declare:

!/bin/bash
printstr(){
echo "hello world"
}
declare -x -f printstr

Затем запустите скрипт с помощью команды source:

source function.sh
$ printstr

Рекурсия

Вы можете вызвать функцию из нее же самой, чтобы сделать рекурсию:

!/bin/bash
printstr(){
echo "hello world"
printstr
}
printstr

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

Локальные переменные в функции

Если вы объявите обычную переменную в функции, то она будет доступной во всем скрипте, это удобно для возврата значения функции, но иногда может понадобиться сделать локальную переменную. Для этого существует команда local:

!/bin/bash
printstr(){
local VAR=$1
echo ${VAR}
}
printstr "Hello World"

Библиотеки функций

Мы можем взять некоторые функции bash и объединить их в одну библиотеку, чтобы иметь возможность одной командой импортировать эти функции. Это делается похожим образом на экспорт функций. Сначала создадим файл библиотеки:

test1(){
echo "Hello World from 1";
}
test2(){
echo "Hello World from 2";
}
test3(){
echo "Hello World from 3";
}

Теперь создадим скрипт, который будет использовать наши функции. Импортировать библиотеку можно с помощью команды source или просто указав имя скрипта:

!/bin/bash
source lib.sh
test1
test2
test3

Выводы

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

Каким бы простым ни был графический интерфейс в Linux и сколько бы там ни было функций, все равно есть задачи, которые удобнее решать через терминал. Во-первых, потому что это быстрее, во-вторых - не на всех машинах есть графический интерфейс, например, на серверах все действия выполняются через терминал, в целях экономии вычислительных ресурсов.

Если вы уже более опытный пользователь, то, наверное, часто выполняете различные задачи через терминал. Часто встречаются задачи, для которых нужно выполнять несколько команд по очереди, например, для обновления системы необходимо сначала выполнить обновление репозиториев, а уже затем скачать новые версии пакетов. Это только пример и таких действий очень много, даже взять резервное копирование и загрузку скопированных файлов на удаленный сервер. Поэтому, чтобы не набирать одни и те же команды несколько раз можно использовать скрипты. В этой статье мы рассмотрим написание скриптов на Bash, рассмотрим основные операторы, а также то как они работают, так сказать, bash скрипты с нуля.

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

Чтобы выполните:

chmod ugo+x файл_скрипта

Теперь выполняем нашу небольшую первую программу:

./файл_скрипта

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

Переменные в скриптах

Написание скриптов на Bash редко обходится без сохранения временных данных, а значит создания переменных. Без переменных не обходится ни один язык программирования и наш примитивный язык командной оболочки тоже.

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

Например, объявим переменную string:

string="Hello world"

Значение нашей строки в кавычках. Но на самом деле кавычки не всегда нужны. Здесь сохраняется главный принцип bash - пробел - это специальный символ, разделитель, поэтому если не использовать кавычки world уже будет считаться отдельной командой, по той же причине мы не ставим пробелов перед и после знака равно.

Чтобы вывести значение переменной используется символ $. Например:

Модифицируем наш скрипт:

!/bin/bash
string1="hello "
string2=world
string=$string1$string2
echo $string

И проверяем:

Bash не различает типов переменных так, как языки высокого уровня, например, С++, вы можете присвоить переменной как число, так и строку. Одинаково все это будет считаться строкой. Оболочка поддерживает только слияние строк, для этого просто запишите имена переменных подряд:

!/bin/bash
string1="hello "
string2=world
string=$string1$string2\ and\ me
string3=$string1$string2" and me"
echo $string3

Проверяем:

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

Переменные и вывод команд

Переменные не были бы настолько полезны, если бы в них невозможно было записать результат выполнения утилит. Для этого используется такой синтаксис:

$(команда )

С помощью этой конструкции вывод команды будет перенаправлен прямо туда, откуда она была вызвана, а не на экран. Например, утилита date возвращает текущую дату. Эти команды эквивалентны:

Понимаете? Напишем скрипт, где будет выводиться hello world и дата:

string1="hello world "
string2=$(date)

string=$string1$string2

Теперь вы знаете достаточно о переменных, и готовы создать bash скрипт, но это еще далеко не все. Дальше мы рассмотрим параметры и управляющие конструкции. Напомню, что это все обычные команды bash, и вам необязательно сохранять их в файле, можно выполнять сразу же на ходу.

Параметры скрипта

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

Переменная с именем 1 содержит значение первого параметра, переменная 2, второго и так далее. Этот bash скрипт выведет значение первого параметра:

!/bin/bash
echo $1

Управляющие конструкции в скриптах

Создание bash скрипта было бы не настолько полезным без возможности анализировать определенные факторы, и выполнять в ответ на них нужные действия. Это довольно-таки сложная тема, но она очень важна для того, чтобы создать bash скрипт.

В 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

Конечно, у этой конструкции более мощные возможности, но это слишком сложно чтобы рассматривать их в этой статье. Возможно, я напишу об этом потом. А пока перейдем к циклам.

Циклы в скриптах

Преимущество программ в том, что мы можем в несколько строчек указать какие действия нужно выполнить несколько раз. Например, возможно написание скриптов на bash, которые состоят всего из нескольких строчек, а выполняются часами, анализируя параметры и выполняя нужные действия.

Первым рассмотрим цикл for. Вот его синтаксис:

for переменная in список
do
команда
done

Перебирает весь список, и присваивает по очереди переменной значение из списка, после каждого присваивания выполняет команды, расположенные между do и done.

Например, переберем пять цифр:

for index in 1 2 3 4 5
do
echo $index
done

Или вы можете перечислить все файлы из текущей директории:

for file in $(ls -l); do echo "$file"; done

Как вы понимаете, можно не только выводить имена, но и выполнять нужные действия, это очень полезно когда выполняется создание bash скрипта.

Второй цикл, который мы рассмотрим - это цикл while, он выполняется пока команда условия возвращает код 0, успех. Рассмотрим синтаксис:

while команда условие
do
команда
done

Рассмотрим пример:

!/bin/bash
index=1
while [[ $index < 5 ]]
do
echo $index
let "index=index+1"
done

Как видите, все выполняется, команда let просто выполняет указанную математическую операцию, в нашем случае увеличивает значение переменной на единицу.

Хотелось бы отметить еще кое-что. Такие конструкции, как while, for, if рассчитаны на запись в несколько строк, и если вы попытаетесь их записать в одну строку, то получите ошибку. Но тем не менее это возможно, для этого там, где должен быть перевод строки ставьте точку с запятой ";". Например, предыдущий цикл можно было выполнить в виде одной строки:

index=1; while [[ $index < 5 ]]; do echo $index; let "index=index+1"; done;

Все очень просто я пытался не усложнять статью дополнительными терминами и возможностями bash, только самое основное. В некоторых случаях, возможно, вам понадобиться сделать gui для bash скрипта , тогда вы можете использовать такие программы как zenity или kdialog, с помощью них очень удобно выводить сообщения пользователю и даже запрашивать у него информацию.

Выводы

Теперь вы понимаете основы создания скрипта в linux и можете написать нужный вам скрипт, например, для резервного копирования. Я пытался рассматривать bash скрипты с нуля. Поэтому далеко не все аспекты были рассмотрены. Возможно, мы еще вернемся к этой теме в одной из следующих статей.

Для написания простого скрипта на bash , нам потребуется выполнить следующие простые действия:

Как это все работает:

первая строка нашего скрипта #!/bin/bash крайне необходима, для того, чтобы наш скрипт успешно выполнился.

вторая строка mkdir testdir создает каталог testdir

третья строка cd testdir позволяет перейти в созданный каталог testdir

команда touch в следующей строке touch file1 file2 file3 создает три файла

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

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

Если вы ежедневно выполняете цепочку каких-либо одинаковых команд (с постоянными параметрами) в Linux, то возможно вам имеет смысл написать такой же простой скрипт на bash , который позволит вам сэкономить ваше время и автоматизировать вашу работу.

Пишем скрипты в Linux (обучение на примерах)

———————————————————————————-

1. Введение

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

Зачем нужны скрипты
Во-первых, администрирование linux-сервера в той или иной степени сводится к систематическому выполнению одних и тех же команд. Причем не обязательно, чтобы эти команды выполнял человек. Их можно запрограммировать на выполнение машиной.
Во-вторых, даже просто выполнение обычной задачи, которая (вдруг) составляет 20-1000… однообразных операций ГОРАЗДО проще реализовать в скрипте.

Что такое скрипт
Скрипт — набор инструкций, которые должен в определенном порядке и в определенное время выполнить компьютер. Инструкциями могут быть как внутренние команды оболочки (циклы, условия, обработка текстовой информации, работа с переменными окружения и прочее), так и любая программа, выполняемая нами в консоли с необходимыми параметрами.

Как писать скрипт
В нашем случае скрипт будет представлять из себя текстовый файл с атрибутами выполнения. Если файл сценария начинается с последовательности #!, которая в мире UNIX называется sha-bang, то это указывает системе какой интерпретатор следует использовать для исполнения сценария. Если это трудно понять, то просто запомните, что все скрипты мы будем начинать писать именно со строчки #!/bin/bash или #!/bin/sh, а далее пойдут команды и комментарии к ним.

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

Какие скрипты могут нам понадобиться:

    устанавливающий правила файервола при загрузке системы.
    выполняющий backup настроек и данных.
    запускающий в определенное время (лучше каждую ночь) программу, которая сканирует логи прокси-сервера и выдает удобный web-отчет по количеству скачанного трафика.
    отправляющий нам на почту информацию о том, что кто-то получил доступ к нашему серверу по ssh, время подключения и адрес клиента.

О методике написания скриптов
Создаем текстовый файл, редактируем его, устанавливаем права на выполнение, запускаем, смотрим ошибки, исправляем, запускаем, смотрим ошибки…
Когда все вылизано и работает правильно, ставим его в автозагрузку либо в планировщик на определенное время.

———————————————————————————-

2. Обучение написанию сценариев на внутреннем языке BASH
оригинал: https://www.linuxconfig.org/Bash_scripting_Tutorial

Это руководство предполагает отсутствие предварительных знаний о методике написания сценариев (далее скриптов) с помощью внутреннего языка Bash. С помощью данного руководства вы обнаружите в скором времени, что написание скриптов очень простая задача. Давайте начнем наше обучение с простого сценария, выполняющего вывод строки «Hello World!» (в перев. с англ. — Всем привет!)

1. Сценарий «Всем привет»
Вот ваш первый пример bash-скрипта:

#!/bin/bash
echo «Hello World»

Переходим в директорию, содержащую наш файл hello_world.sh и делаем его исполняемым:

Код: Выделить всё $ chmod +x hello_world.sh

Запускаем скрипт на выполнение

Код: Выделить всё $ ./hello_world.sh

2. Простой архивирующий bash-скрипт

#!/bin/bash
tar -czf myhome_directory.tar.gz /home/user

Код: Выделить всё $ ./backup.sh

$ du -sh myhome_directory.tar.gz
41M myhome_directory.tar.gz

3. Работа с переменными
В данном примере мы объявляем простую переменную и выводим её на экран с помощью команды echo

#!/bin/bash
STRING=»HELLO WORLD!!!»
echo $STRING

Код: Выделить всё $ ./hello_world.sh
HELLO WORLD!!!

Наш архивирующий скрипт с переменными:

#!/bin/bash
OF=myhome_directory_$(date +%Y%m%d).tar.gz
IF=/home/user
tar -czf $OF $IF

Код: Выделить всё $ ./backup.sh
tar: Removing leading "\" from member names
$ du -sh *tar.gz
41M myhome_directory_20100123.tar.gz

3.1 Глобальные и локальные переменные

#!/bin/bash
# Объявляем глобальную переменную
# Такая переменная может использоваться в любом месте этого скрипта
VAR=»global variable»
function bash {
# Объявляем локальную переменную
# Такая переменная действительна только для функции, в которой её объявили
local VAR=»local variable»
echo $VAR
}
echo $VAR
bash
# Обратите внимание, что глобальная переменная не изменилась
echo $VAR

Код: Выделить всё $ ./variables.sh
global variable
local variable
global variable

4. Передаем аргументы в скрипт

#!/bin/bash
# Используйте предопределенные переменные для доступа к аргументам
# Выводим аргументы на экран
echo $1 $2 $3 ‘ -> echo $1 $2 $3’

#Мы так же можем получить доступ к аргументам через специальный массив args=(«$@»)
# Выводим аргументы на экран
echo ${args} ${args} ${args} ‘ -> args=(«$@»); echo ${args} ${args} ${args}’

# Используйте переменную $@ для вывода всех аргументов сразу
echo $@ ‘ -> echo $@’

Используйте переменную $# для вывода количества переданный в скрипт аргументов
echo Number of arguments passed: $# ‘ -> echo Number of arguments passed: $#’

Код: Выделить всё $ ./arguments.sh Bash Scripting Tutorial
Bash Scripting Tutorial -> echo $1 $2 $3
Bash Scripting Tutorial -> args=("$@"); echo ${args} ${args} ${args}
Bash Scripting Tutorial -> echo $@
Number of arguments passed: 3 -> echo Number of arguments passed: $#

5. Выполнение в скрипте команд оболочки

#!/bin/bash
# используйте обратные кавычки » ` ` » для выполнения команды оболочки
echo `uname -o`
# теперь попробуем без кавычек
echo uname -o

Код: Выделить всё $ uname -o
GNU/Linux
$ ./bash_backtricks.sh
GNU/Linux
uname -o

Как видим, во втором случае вывелась сама команда, а не результат её выполнения

6. Читаем пользовательский ввод (интерактивность)

#!/bin/bash
echo -e «Hi, please type the word: \c »
read word
echo «The word you entered is: $word»
echo -e «Can you please enter two words? »
read word1 word2
echo «Here is your input: \»$word1\» \»$word2\»»
echo -e «How do you feel about bash scripting? »
# read command now stores a reply into the default build-in variable $REPLY
read
echo «You said $REPLY, I’m glad to hear that! »
echo -e «What are your favorite colours ? »
# -a makes read command to read into an array
read -a colours
echo «My favorite colours are also ${colours}, ${colours} and ${colours}:-)»

Код: Выделить всё $ ./read.sh
Hi, please type the word: something
The word you entered is: something
Can you please enter two words?
Debian Linux
Here is your input: "Debian" "Linux"
How do you feel about bash scripting?
good
You said good, I"m glad to hear that!
What are your favorite colours ?
blue green black
My favorite colours are also blue, green and black:-)

7. Использование ловушки

#!/bin/bash
# объявляем ловушку
trap bashtrap INT
# очищаем экран
clear;
# функция ловушки выполняется, когда пользователь нажимает CTRL-C:
# На экран будет выводиться => Executing bash trap subrutine !
# но скрипт будет продолжать выполняться
bashtrap()
{
echo «CTRL+C Detected !…executing bash trap !»
}
# скрипт будет считать до 10
for a in `seq 1 10`; do
echo «$a/10 to Exit.»
sleep 1;
done
echo «Exit Bash Trap Example!!!»

Код: Выделить всё $ ./trap.sh
1/10
2/10
3/10
4/10
5/10
6/10

7/10
8/10
9/10
CTRL+C Detected !...executing bash trap !
10/10
Exit Bash Trap Example!!!

Как видим, сочетание клавишь Ctrl-C не остановило выполнение скрипта.

8. Массивы
8.1 Объявляем простой массив

#!/bin/bash
# Объявляем простой массив с 4 элементами
ARRAY=(‘Debian Linux’ ‘Redhat Linux’ Ubuntu Linux)
# Получаем количество элементов в массиве
ELEMENTS=${#ARRAY[@]}

# выводим в цикле каждый элемент массива
for ((i=0;i<$ELEMENTS;i++)); do
echo ${ARRAY[${i}]}
done

Код: Выделить всё $./arrays.sh
Debian Linux
Redhat Linux
Ubuntu
Linux

8.2 Заполняем массив значениями из файла

#!/bin/bash
# Объявляем массив
declare -a ARRAY
# Команда exec # stdin (обычно это клавиатура), будет производиться из этого файла. Это дает возможность читать
# содержимое файла, строку за строкой, и анализировать каждую введенную строку с помощью sed и/или awk.
exec 10 let count=0

while read LINE <&10; do

ARRAY[$count]=$LINE
((count++))
done

echo Number of elements: ${#ARRAY[@]}
# Вывод значений массива
echo ${ARRAY[@]}
# закрываем файл
exec 10>&-

Код: Выделить всё $ cat bash.txt
Debian Linux
Redhat Linux
Ubuntu
Linux
$ ./arrays.sh
Number of elements: 4
Debian Linux Redhat Linux Ubuntu Linux

9. Условия «если-то-иначе»
9.1. Простое использование «если-иначе» условий
Обратите внимание на пробелы в квадратных скобках, без которых условие работать не будет.

#!/bin/bash
directory=»./BashScripting»

# проверяем наличие директории
if [ -d $directory ]; then
echo «Directory exists»
else
echo «Directory does not exists»
fi

Код: Выделить всё $ ./if_else.sh
Directory does not exists
$ mkdir BashScripting
$ ./if_else.sh
Directory exists

9.2 Вложенные «если-иначе» условия

#!/bin/bash
# Объявляем переменную со значением 4
choice=4
# Выводим на экран
echo «1. Bash»
echo «2. Scripting»
echo «3. Tutorial»

# Выполняем, пока переменная равна четырем
# Зацикливание
while [ $choice -eq 4 ]; do

# читаем пользовательский ввод
read choice
# вложенное «если-иначе» условие
if [ $choice -eq 1 ] ; then

echo «You have chosen word: Bash»

if [ $choice -eq 2 ] ; then
echo «You have chosen word: Scripting»
else

if [ $choice -eq 3 ] ; then
echo «You have chosen word: Tutorial»
else
echo «Please make a choice between 1-3 !»
echo «1. Bash»
echo «2. Scripting»
echo «3. Tutorial»
echo -n «Please choose a word ? »
choice=4
fi
fi
fi
done

Код: Выделить всё $ ./nested.sh
1. Bash
2. Scripting
3. Tutorial

5

1. Bash
2. Scripting
3. Tutorial
Please choose a word ?
4
Please make a choice between 1-3 !
1. Bash
2. Scripting
3. Tutorial
Please choose a word ?
3
You have chosen word: Tutorial

Таким образом сначала тело цикла «while» выполняется, т.к. переменная choice изначально равна четырем. Потом читаем в неё пользовательский ввод, и если ввод не равен 1,2 или 3 то делаем нашу переменную снова равную 4, в связи с чем тело цикла повторяется (снова необходимо вводить 1,2 или 3).

10. Сравнения
10.1 Арифметические сравнения

Lt <
-gt >
-le <=
-ge >=
-eq ==
-ne !=

#!/bin/bash

NUM1=2
NUM2=2
if [ $NUM1 -eq $NUM2 ]; then
echo «Both Values are equal»
else
echo «Values are NOT equal»
fi

Код: Выделить всё $ ./equals.sh
Both Values are equal

#!/bin/bash
# Объявляем переменные с целочисленными значениями
NUM1=2
NUM2=3
if [ $NUM1 -eq $NUM2 ]; then
echo «Both Values are equal»
else
echo «Values are NOT equal»
fi

Код: Выделить всё $ ./equals.sh
Values are NOT equal

#!/bin/bash
# Объявляем переменные с целочисленными значениями
NUM1=2
NUM2=1
if [ $NUM1 -eq $NUM2 ]; then
echo «Both Values are equal»
elif [ $NUM1 -gt $NUM2 ]; then
echo «$NUM1 is greater then $NUM2»
else
echo «$NUM2 is greater then $NUM1»
fi

Код: Выделить всё $ ./equals.sh
2 is greater then 1

10.2 Символьно-текстовые сравнения

Одинаковые
!= не одинаковые
< меньще чем
> больше чем
-n s1 переменная s1 не пустая
-z s1 переменная s1 пустая

#!/bin/bash

S1=»Bash»

S2=»Scripting»
if [ $S1 = $S2 ]; then

else
echo «Strings are NOT equal»
fi

Код: Выделить всё $ ./statement.sh
Strings are NOT equal

#!/bin/bash
# Объявляем символьную переменную S1
S1=»Bash»
# Объявляем символьную переменную S2
S2=»Bash»
if [ $S1 = $S2 ]; then
echo «Both Strings are equal»
else
echo «Strings are NOT equal»
fi

Код: Выделить всё $ ./statement.sh
Both Strings are equal

11. Проверка файлов

B filename Block special file
-c filename Special character file
-d directoryname Check for directory existence
-e filename Check for file existence
-f filename Check for regular file existence not a directory
-G filename Check if file exists and is owned by effective group ID.
-g filename true if file exists and is set-group-id.
-k filename Sticky bit
-L filename Symbolic link
-O filename True if file exists and is owned by the effective user id.
-r filename Check if file is a readable
-S filename Check if file is socket
-s filename Check if file is nonzero size
-u filename Check if file set-ser-id bit is set
-w filename Check if file is writable
-x filename Check if file is executable

#!/bin/bash
file=»./file»
if [ -e $file ]; then
echo «File exists»
else
echo «File does not exists»
fi

Код: Выделить всё $ ls
file.sh
$ ./file.sh
File does not exists
$ touch file
$ ls
file file.sh
$ ./file.sh
File exists

Аналогично для примера мы можем использовать «в то время как» петли, чтобы проверить, если файл не существует. Этот сценарий будет спать, пока файл не существует. Обратите внимание на Bash отрицатель «!» что сводит на нет (инвертирует) -e опцию.

12. Циклы
12.1. Цикл For

#!/bin/bash
# for цикл
for f in $(ls /var/); do
echo $f
done

Запуск for-цикла из командной строки bash:

Код: Выделить всё $ for f in $(ls /var/); do echo $f; done Код: Выделить всё $ for f in $(ls /var/); do echo $f; done
backups
cache
crash
games
lib
local
lock
log
mail
opt
run
spool
tmp
www

12.2. While цикл

#!/bin/bash
COUNT=6
# while цикл
while [ $COUNT -gt 0 ]; do

let COUNT=COUNT-1
done

Код: Выделить всё $ ./while_loop.sh
Value of count is: 6
Value of count is: 5
Value of count is: 4
Value of count is: 3
Value of count is: 2
Value of count is: 1

12.3. Until цикл

#!/bin/bash
COUNT=0
# until цикл
until [ $COUNT -gt 5 ]; do
echo Value of count is: $COUNT
let COUNT=COUNT+1
done

Код: Выделить всё $ ./until_loop.sh
Value of count is: 0
Value of count is: 1
Value of count is: 2
Value of count is: 3
Value of count is: 4
Value of count is: 5

12.4. Циклы с неявными условиями
В следующем примере условием while-цикла является наличие стандартного ввода.
Тело цикла будет выполняться пока есть чему перенаправляться из стандартного вывода в команду read.

#!/bin/bash
# Данный скрипт будет искать и удалять пробелы
# в файлах, заменяя их на подчеркивания
DIR=».»
Управление циклом с командой read путем перенаправления вывода в цикле.
find $DIR -type f | while read file; do
# используем POSIX-класс [:space:] чтобы найти пробелы в именах файлов
if [[ «$file» = *[[:space:]]* ]]; then
# замена пробелов подчеркиваниями
mv «$file» `echo $file | tr ‘ ‘ ‘_’`
fi;
done

Код: Выделить всё $ ls -1
script.sh
$ touch "file with spaces"
$ ls -1
file with spaces
script.sh
$ ./script.sh
$ ls -1
file_with_spaces
script.sh

13. Функции

#!/bin/bash
# Функции могут быть объявлены в любом порядке
function function_B {
echo Function B.
}
function function_A {
echo $1
}
function function_D {
echo Function D.
}
function function_C {
echo $1
}
# Вызываем функции
# передаем параметр в функцию function A
function_A «Function A.»
function_B
# передаем параметр в функцию function C
function_C «Function C.»
function_D

Код: Выделить всё $ ./functions.sh
Function A.
Function B.
Function C.
Function D.

14. Оператор выбора — Select

#!/bin/bash
PS3=’Choose one word: ‘
# select
select word in «linux» «bash» «scripting» «tutorial»
do
echo «The word you have selected is: $word»
# Прерываем, в противном случае цикл будет бесконечный.
break
done
exit 0

Код: Выделить всё $ ./select.sh
1) linux
2) bash
3) scripting
4) tutorial
Choose one word: 4
The word you have selected is: tutorial

15. Оператор выбора — Case

#!/bin/bash
echo «What is your preferred programming / scripting language»
echo «1) bash»
echo «2) perl»
echo «3) phyton»
echo «4) c++»
echo «5) I do not know !»
read case;
# простая структура case-выбора
# обратите внимание, что в данном примере $case — всего лишь переменная
# и не обязана так называться. Это лишь пример
case $case in
1) echo «You selected bash»;;
2) echo «You selected perl»;;
3) echo «You selected phyton»;;
4) echo «You selected c++»;;
5) exit
esac

Код: Выделить всё $ ./case.sh
What is your preferred programming / scripting language
1) bash
2) perl
3) phyton
4) c++
5) I do not know !
4
You selected c++

———————————————————————————-

Более подробную информацию можно получить из различных источников, например отсюда
оригинал: https://www.linuxconfig.org/Bash_scripting_Tutorial
https://ruslandh.narod.ru/howto_ru/Bash-Prog-Intro/
https://bug.cf1.ru/2005-03-17/programmin … -book.html

https://ubuntologia.ru/forum/viewtopic.php?f=109&t=2296

Сегодня поговорим о bash-скриптах. Это - сценарии командной строки , написанные для оболочки bash. Существуют и другие оболочки, например - zsh, tcsh, ksh, но мы сосредоточимся на bash. Этот материал предназначен для всех желающих, единственное условие - умение работать в командной строке Linux.



Сценарии командной строки - это наборы тех же самых команд, которые можно вводить с клавиатуры, собранные в файлы и объединённые некоей общей целью. При этом результаты работы команд могут представлять либо самостоятельную ценность, либо служить входными данными для других команд. Сценарии - это мощный способ автоматизации часто выполняемых действий.

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

Pwd ; whoami
На самом деле, если вы опробовали это в своём терминале, ваш первый bash-скрипт, в котором задействованы две команды, уже написан. Работает он так. Сначала команда pwd выводит на экран сведения о текущей рабочей директории, потом команда whoami показывает данные о пользователе, под которым вы вошли в систему.

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

Getconf ARG_MAX
Командная строка - отличный инструмент, но команды в неё приходится вводить каждый раз, когда в них возникает необходимость. Что если записать набор команд в файл и просто вызывать этот файл для их выполнения? Собственно говоря, тот файл, о котором мы говорим, и называется сценарием командной строки.

Как устроены bash-скрипты

Создайте пустой файл с использованием команды touch . В его первой строке нужно указать, какую именно оболочку мы собираемся использовать. Нас интересует bash , поэтому первая строка файла будет такой:

#!/bin/bash
В других строках этого файла символ решётки используется для обозначения комментариев, которые оболочка не обрабатывает. Однако, первая строка - это особый случай, здесь решётка, за которой следует восклицательный знак (эту последовательность называют шебанг) и путь к bash , указывают системе на то, что сценарий создан именно для bash .

Команды оболочки отделяются знаком перевода строки, комментарии выделяют знаком решётки. Вот как это выглядит:

#!/bin/bash # This is a comment pwd whoami
Тут, так же, как и в командной строке, можно записывать команды в одной строке, разделяя точкой с запятой. Однако, если писать команды на разных строках, файл легче читать. В любом случае оболочка их обработает.

Установка разрешений для файла сценария

Сохраните файл, дав ему имя myscript , и работа по созданию bash-скрипта почти закончена. Сейчас осталось лишь сделать этот файл исполняемым, иначе, попытавшись его запустить, вы столкнётесь с ошибкой Permission denied .


Попытка запуска файла сценария с неправильно настроенными разрешениями

Сделаем файл исполняемым:

Chmod +x ./myscript
Теперь попытаемся его выполнить:

./myscript
После настройки разрешений всё работает как надо.


Успешный запуск bash-скрипта

Вывод сообщений

Для вывода текста в консоль Linux применяется команда echo . Воспользуемся знанием этого факта и отредактируем наш скрипт, добавив пояснения к данным, которые выводят уже имеющиеся в нём команды:

#!/bin/bash # our comment is here echo "The current directory is:" pwd echo "The user logged in is:" whoami
Вот что получится после запуска обновлённого скрипта.


Вывод сообщений из скрипта

Теперь мы можем выводить поясняющие надписи, используя команду echo . Если вы не знаете, как отредактировать файл, пользуясь средствами Linux, или раньше не встречались с командой echo , взгляните на этот материал.

Использование переменных

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

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

Существуют два типа переменных, которые можно использовать в bash-скриптах:

  • Переменные среды
  • Пользовательские переменные

Переменные среды

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

#!/bin/bash # display user home echo "Home for the current user is: $HOME"
Обратите внимание на то, что мы можем использовать системную переменную $HOME в двойных кавычках, это не помешает системе её распознать. Вот что получится, если выполнить вышеприведённый сценарий.


Использование переменной среды в сценарии

А что если надо вывести на экран значок доллара? Попробуем так:

Echo "I have $1 in my pocket"
Система обнаружит знак доллара в строке, ограниченной кавычками, и решит, что мы сослались на переменную. Скрипт попытается вывести на экран значение неопределённой переменной $1 . Это не то, что нам нужно. Что делать?

В подобной ситуации поможет использование управляющего символа, обратной косой черты, перед знаком доллара:

Echo "I have \$1 in my pocket"
Теперь сценарий выведет именно то, что ожидается.


Использование управляющей последовательности для вывода знака доллара

Пользовательские переменные

В дополнение к переменным среды, bash-скрипты позволяют задавать и использовать в сценарии собственные переменные. Подобные переменные хранят значение до тех пор, пока не завершится выполнение сценария.

Как и в случае с системными переменными, к пользовательским переменным можно обращаться, используя знак доллара:
TNW-CUS-FMP - промо-код на 10% скидку на наши услуги, доступен для активации в течение 7 дней
#!/bin/bash # testing variables grade=5 person="Adam" echo "$person is a good boy, he is in grade $grade"
Вот что получится после запуска такого сценария.


Пользовательские переменные в сценарии

Подстановка команд

Одна из самых полезных возможностей bash-скриптов - это возможность извлекать информацию из вывода команд и назначать её переменным, что позволяет использовать эту информацию где угодно в файле сценария.

Сделать это можно двумя способами.

  • С помощью значка обратного апострофа «`»
  • С помощью конструкции $()
Используя первый подход, проследите за тем, чтобы вместо обратного апострофа не ввести одиночную кавычку. Команду нужно заключить в два таких значка:

Mydir=`pwd`
При втором подходе то же самое записывают так:

Mydir=$(pwd)
А скрипт, в итоге, может выглядеть так:

#!/bin/bash mydir=$(pwd) echo $mydir
В ходе его работы вывод команды pwd будет сохранён в переменной mydir , содержимое которой, с помощью команды echo , попадёт в консоль.


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

Математические операции

Для выполнения математических операций в файле скрипта можно использовать конструкцию вида $((a+b)) :

#!/bin/bash var1=$((5 + 5)) echo $var1 var2=$(($var1 * 2)) echo $var2


Математические операции в сценарии

Управляющая конструкция if-then

В некоторых сценариях требуется управлять потоком исполнения команд. Например, если некое значение больше пяти, нужно выполнить одно действие, в противном случае - другое. Подобное применимо в очень многих ситуациях, и здесь нам поможет управляющая конструкция if-then . В наиболее простом виде она выглядит так:

If команда then команды fi
А вот рабочий пример:

#!/bin/bash if pwd then echo "It works" fi
В данном случае, если выполнение команды pwd завершится успешно, в консоль будет выведен текст «it works».

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

#!/bin/bash user=likegeeks if grep $user /etc/passwd then echo "The user $user Exists" fi
Вот что получается после запуска этого скрипта.


Поиск пользователя

Здесь мы воспользовались командой grep для поиска пользователя в файле /etc/passwd . Если команда grep вам незнакома, её описание можно найти .

В этом примере, если пользователь найден, скрипт выведет соответствующее сообщение. А если найти пользователя не удалось? В данном случае скрипт просто завершит выполнение, ничего нам не сообщив. Хотелось бы, чтобы он сказал нам и об этом, поэтому усовершенствуем код.

Управляющая конструкция if-then-else

Для того, чтобы программа смогла сообщить и о результатах успешного поиска, и о неудаче, воспользуемся конструкцией if-then-else . Вот как она устроена:

If команда then команды else команды fi
Если первая команда возвратит ноль, что означает её успешное выполнение, условие окажется истинным и выполнение не пойдёт по ветке else . В противном случае, если будет возвращено что-то, отличающееся от нуля, что будет означать неудачу, или ложный результат, будут выполнены команды, расположенные после else .

Напишем такой скрипт:

#!/bin/bash user=anotherUser if grep $user /etc/passwd then echo "The user $user Exists" else echo "The user $user doesn’t exist" fi
Его исполнение пошло по ветке else .


Запуск скрипта с конструкцией if-then-else

Ну что же, продолжаем двигаться дальше и зададимся вопросом о более сложных условиях. Что если надо проверить не одно условие, а несколько? Например, если нужный пользователь найден, надо вывести одно сообщение, если выполняется ещё какое-то условие - ещё одно сообщение, и так далее. В подобной ситуации нам помогут вложенные условия. Выглядит это так:

If команда1 then команды elif команда2 then команды fi
Если первая команда вернёт ноль, что говорит о её успешном выполнении, выполнятся команды в первом блоке then , иначе, если первое условие окажется ложным, и если вторая команда вернёт ноль, выполнится второй блок кода.

#!/bin/bash user=anotherUser if grep $user /etc/passwd then echo "The user $user Exists" elif ls /home then echo "The user doesn’t exist but anyway there is a directory under /home" fi
В подобном скрипте можно, например, создавать нового пользователя с помощью команды useradd , если поиск не дал результатов, или делать ещё что-нибудь полезное.

Сравнение чисел

В скриптах можно сравнивать числовые значения. Ниже приведён список соответствующих команд.
n1 -eq n2 Возвращает истинное значение, если n1 равно n2 .
n1 -ge n2 Возвращает истинное значение, если n1 больше или равно n2 .
n1 -gt n2 Возвращает истинное значение, если n1 больше n2 .
n1 -le n2 Возвращает истинное значение, если n1 меньше или равно n2 .
n1 -lt n2 Возвращает истинное значение, если n1 меньше n2 .
n1 -ne n2 Возвращает истинное значение, если n1 не равно n2 .

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

#!/bin/bash val1=6 if [ $val1 -gt 5 ] then echo "The test value $val1 is greater than 5" else echo "The test value $val1 is not greater than 5" fi
Вот что выведет эта команда.


Сравнение чисел в скриптах

Значение переменной val1 больше чем 5, в итоге выполняется ветвь then оператора сравнения и в консоль выводится соответствующее сообщение.

Сравнение строк

В сценариях можно сравнивать и строковые значения. Операторы сравнения выглядят довольно просто, однако у операций сравнения строк есть определённые особенности, которых мы коснёмся ниже. Вот список операторов.
str1 = str2 Проверяет строки на равенство, возвращает истину, если строки идентичны.
s tr1 != str2 Возвращает истину, если строки не идентичны.
str1 < str2 Возвращает истину, если str1 меньше, чем str2 .
str1 > str2 Возвращает истину, если str1 больше, чем str2 .
-n str1 Возвращает истину, если длина str1 больше нуля.
-z str1 Возвращает истину, если длина str1 равна нулю.

Вот пример сравнения строк в сценарии:

#!/bin/bash user ="likegeeks" if [$user = $USER] then echo "The user $user is the current logged in user" fi
В результате выполнения скрипта получим следующее.


Сравнение строк в скриптах

Вот одна особенность сравнения строк, о которой стоит упомянуть. А именно, операторы «>» и «<» необходимо экранировать с помощью обратной косой черты, иначе скрипт будет работать неправильно, хотя сообщений об ошибках и не появится. Скрипт интерпретирует знак «>» как команду перенаправления вывода.

Вот как работа с этими операторами выглядит в коде:

#!/bin/bash val1=text val2="another text" if [ $val1 \>
Вот результаты работы скрипта.


Сравнение строк, выведенное предупреждение

Обратите внимание на то, что скрипт, хотя и выполняется, выдаёт предупреждение:

./myscript: line 5: [: too many arguments
Для того, чтобы избавиться от этого предупреждения, заключим $val2 в двойные кавычки:

#!/bin/bash val1=text val2="another text" if [ $val1 \> "$val2" ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi
Теперь всё работает как надо.


Сравнение строк

Ещё одна особенность операторов «>» и «<» заключается в том, как они работают с символами в верхнем и нижнем регистрах. Для того, чтобы понять эту особенность, подготовим текстовый файл с таким содержимым:

Likegeeks likegeeks
Сохраним его, дав имя myfile , после чего выполним в терминале такую команду:

Sort myfile
Она отсортирует строки из файла так:

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

#!/bin/bash val1=Likegeeks val2=likegeeks if [ $val1 \> $val2 ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi
Если его запустить, окажется, что всё наоборот - строчная буква теперь больше прописной.


Команда sort и сравнение строк в файле сценария

В командах сравнения прописные буквы меньше строчных. Сравнение строк здесь выполняется путём сравнения ASCII-кодов символов, порядок сортировки, таким образом, зависит от кодов символов.

Команда sort , в свою очередь, использует порядок сортировки, заданный в настройках системного языка.

Проверки файлов

Пожалуй, нижеприведённые команды используются в bash-скриптах чаще всего. Они позволяют проверять различные условия, касающиеся файлов. Вот список этих команд.
-d file Проверяет, существует ли файл, и является ли он директорией.
-e file Проверяет, существует ли файл.
-f file Проверяет, существует ли файл, и является ли он файлом.
-r file Проверяет, существует ли файл, и доступен ли он для чтения.
-s file П роверяет, существует ли файл, и не является ли он пустым.
-w file Проверяет, существует ли файл, и доступен ли он для записи.
-x file Проверяет, существует ли файл, и является ли он исполняемым.
file1 -nt file2 Проверяет, новее ли file1 , чем file2 .
file1 -ot file2 Проверяет, старше ли file1 , чем file2 .
-O file Проверяет, существует ли файл, и является ли его владельцем текущий пользователь.
-G file Проверяет, существует ли файл, и соответствует ли его идентификатор группы идентификатору группы текущего пользователя.

Эти команды, как впрочем, и многие другие рассмотренные сегодня, несложно запомнить. Их имена, являясь сокращениями от различных слов, прямо указывают на выполняемые ими проверки.

Опробуем одну из команд на практике:

#!/bin/bash mydir=/home/likegeeks if [ -d $mydir ] then echo "The $mydir directory exists" cd $ mydir ls else echo "The $mydir directory does not exist" fi
Этот скрипт, для существующей директории, выведет её содержимое.


Вывод содержимого директории

Полагаем, с остальными командами вы сможете поэкспериментировать самостоятельно, все они применяются по тому же принципу.

Итоги

Сегодня мы рассказали о том, как приступить к написанию bash-скриптов и рассмотрели некоторые базовые вещи. На самом деле, тема bash-программирования огромна. Эта статья является переводом первой части большой серии из 11 материалов. Если вы хотите продолжения прямо сейчас - вот список оригиналов этих материалов. Для удобства сюда включён и тот, перевод которого вы только что прочли.
mob_info