Bash-скрипты, руководство в 11 частях — страница 10 из 19


Функция не может напрямую использовать параметры, переданные сценарию

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


#!/bin/bash

function myfunc {

echo $(( $1 + $2 ))

}

if [ $# -eq 2 ]

then

value=$(myfunc $1 $2)

echo "The result is $value"

else

echo "Usage: myfunc a b"

fi

Теперь всё работает правильно.


Передача функции параметров, с которыми запущен скрипт

Работа с переменными в функциях


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


Существуют два вида переменных:


   • Глобальные переменные.

   • Локальные переменные.

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


Глобальные переменные — это переменные, которые видны из любого места bash-скрипта. Если вы объявили глобальную переменную в основном коде скрипта, к такой переменной можно обратиться из функции.


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


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


#!/bin/bash

function myfunc {

value=$(( $value + 10 ))

}

read -p "Enter a value: " value

myfunc

echo "The new value is: $value"

Вот что выведет этот сценарий.


Обращение к глобальной переменной из функции

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


Что если такое поведение нас не устраивает? Ответ прост — надо использовать локальные переменные.

Локальные переменные


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


local temp=$(( $value + 5 ))

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


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


#!/bin/bash

function myfunc {

local temp=$[ $value + 5 ]

echo "The Temp from inside function is $temp"

}

temp=4

myfunc

echo "The temp from outside is $temp"

Запустим скрипт.


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

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

Передача функциям массивов в качестве аргументов


Попробуем передать функции в качестве аргумента массив. Сразу хочется сказать, что работать такая конструкция будет неправильно:


#!/bin/bash

function myfunc {

echo "The parameters are: $@"

arr=$1

echo "The received array is ${arr[*]}"

}

myarray=(1 2 3 4 5)

echo "The original array is: ${myarray[*]}"

myfunc $myarray

Неправильный подход к передаче функциям массивов

Как видно из примера, при передаче функции массива, она получит доступ лишь к его первому элементу.


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


#!/bin/bash

function myfunc {

local newarray

newarray=("$@")

echo "The new array value is: ${newarray[*]}"

}

myarray=(1 2 3 4 5)

echo "The original array is ${myarray[*]}"

myfunc ${myarray[*]}

Запустим сценарий.


Сборка массива внутри функции

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

Рекурсивные функции


Рекурсия — это когда функция сама себя вызывает. Классический пример рекурсии — функция для вычисления факториала. Факториал числа — это произведение всех натуральных чисел от 1 до этого числа. Например, факториал 5 можно найти так:


5! = 1 * 2 * 3 * 4 * 5

Если формулу вычисления факториала написать в рекурсивном виде, получится следующее:


x! = x * (x-1)!

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


#!/bin/bash

function factorial {

if [ $1 -eq 1 ]

then

echo 1

else

local temp=$(( $1 - 1 ))

local result=$(factorial $temp)

echo $(( $result * $1 ))

fi

}

read -p "Enter value: " value

result=$(factorial $value)

echo "The factorial of $value is: $result"

Проверим, верно ли работает этот скрипт.


Вычисление факториала

Как видите, всё работает как надо.

Создание и использование библиотек


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


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


Ключ к использованию библиотек — в команде source. Эта команда используется для подключения библиотек к скриптам. В результате функции, объявленные в библиотеке, становятся доступными в скрипте, в противном же случае функции из библиотек не будут доступны в области видимости других скриптов.


У команды source есть псевдоним — оператор «точка». Для того, чтобы подключить файл в скрипте, в скрипт надо добавить конструкцию такого вида:


. ./myscript

Предположим, что у нас имеется файл myfuncs, который содержит следующее:


function addnum {

echo $(( $1 + $2 ))

}

Это — библиотека. Воспользуемся ей в сценарии:


#!/bin/bash

. ./myfuncs

result=$(addnum 10 20)

echo "The result is: $result"

Вызовем его.


Использование библиотек

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

Вызов bash-функций из командной строки


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


Отредактируйте .bashrc, добавив в него такую строку (путь к файлу библиотеки в вашей системе, естественно, будет другим):


. /home/likegeeks/Desktop/myfuncs

Теперь функцию можно вызывать прямо из командной строки:


$ addnum 10 20

Вызов функции из командной строки

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


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

Итоги


Функции в bash-скриптах позволяют оформлять блоки кода и вызывать их в скриптах. А наиболее часто используемые функции стоит выделить в библиотеки, которые можно подключать к скриптам, используя оператор source. Если же среди ваших функций найдутся такие, без которых вы прямо таки жить не можете — библиотеки с ними можно подключить в файле .bashrc. Это позволит удобно пользоваться ими в командной строке или в других скриптах. Главное — чтобы имена ваших функций не совпадали с именами встроенных команд.


На сегодня это всё. В следующий раз поговорим об утилите sed — мощном средстве обработки строк.


Bash-скрипты, часть 7: sed и обработка текстов


В прошлый раз мы говорили о функциях в bash-скриптах, в частности, о том, как вызывать их из командной строки. Наша сегодняшняя тема — весьма полезный инструмент для обработки строковых данных — утилита Linux, которая называется sed. Её часто используют для работы с текстами, имеющими вид лог-файлов, конфигурационных и других файлов.


Если вы, в bash-скриптах, каким-то образом обрабатываете данные, вам не помешает знакомство с инструментами sed и gawk. Тут мы сосредоточимся на sed и на работе с текстами, так как это — очень важный шаг в нашем путешествии по бескрайним просторам разработки bash-скриптов.


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

Основы работы с sed


Утилиту sed называют потоковым текстовым редактором. В интерактивных текстовых редакторах, наподобие nano, с текстами работают, используя клавиатуру, редактируя файлы, добавляя, удаляя или изменяя тексты. Sed позволяет редактировать потоки данных, основываясь на заданных разработчиком наборах правил. Вот как выглядит схема вызова этой команды: