Сценарии оболочки, часть V: Функции в Bash
На этой странице
- Введение
- Общий синтаксис:
Привет! Добро пожаловать в серию руководств по написанию сценариев оболочки HowToForges. Если вы хотите прочитать предыдущие выпуски руководства, не стесняйтесь щелкнуть здесь, чтобы перейти к части 4 руководства. В этой части вы узнаете, как эффективно структурировать свои скрипты, создавая функции. К концу этого руководства вы сможете узнать, как создавать функции в оболочке Bash Linux, передавать параметры в ваши функции и возвращать некоторые значения из функции в ваш основной код. Давайте начнем!
Вступление
Функция, также известная как подпрограмма в языках программирования, представляет собой набор инструкций, которые выполняют определенную задачу для основной процедуры [1]. Это позволяет программистам разбивать сложный и длинный код на небольшие разделы, которые можно вызывать при необходимости. Каждая функция должна быть вызвана основной подпрограммой для запуска, таким образом, она изолирована от других частей вашего кода, и это создает простой способ тестирования кода. Кроме того, функции можно вызывать в любое время и многократно, что позволяет повторно использовать, оптимизировать и минимизировать коды. Как и большинство языков программирования, оболочка bash также поддерживает функции.
Общий синтаксис:
- Syntax 1:
function function_name
{
##### set of commands
} - Syntax 2:
function_name()
{
#### set of commands
}
Создание функций
Bash поддерживает две структуры для функций. При использовании первого синтаксиса вы должны использовать ключевое слово function, за которым следует имя вашей функции, а также открывающие и закрывающие круглые скобки и фигурные скобки, чтобы отделить содержимое ваших функций от вашей основной процедуры. Этот синтаксис покажется вам знакомым, если у вас есть опыт работы с PHP, потому что функции в PHP объявляются таким же образом. Другой синтаксис состоит только из имени функции, открывающих и закрывающих скобок и фигурных скобок.
#!/bin/bash
myfunction(){
echo "My function works!"
}
myfunctionВ нашем примере я использовал второй синтаксис. После создания функции myfunction она вызывалась вызовом имени ее функции в нашей основной подпрограмме. Основная подпрограмма будет находиться в любом месте нашего скрипта, которое не было определено как часть нашей функции.
Теперь давайте изменим наш код, чтобы проверить, можно ли объявлять функции в любом месте нашего скрипта. Рассмотрим код ниже:
#!/bin/bash
echo "testing my function"
myfunction
myfunction(){
echo "My function works!"
}Строка 3 в приведенном выше коде возвращает ошибку «команда не найдена». Это означает только то, что:
The function only works if it is declared before your main routine. The interpreter will return an error if you have declared your function after your main routine.
Реструктуризация кодов с использованием функций
Одной из лучших особенностей функций является возможность повторного использования кодов. Когда процедура требует многократного выполнения команд, но не может быть структурирована с помощью операторов цикла, тогда решением может быть функция.
Например, рассмотрим код ниже:
#!/bin/bash
while(true)
do
clear
printf "Choose from the following operations: \n"
printf "[a]ddition\n[b]Subtraction\n[c]Multiplication\n[d]Division\n"
printf "################################\n"
read -p "Your choice: " choice
case $choice in
[aA])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1+int2))
;;
[bB])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1-int2))
;;
[cC])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1*int2))
;;
[dD])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1/int2))
;;
*)
res=0
echo "wrong choice!"
esac
echo "The result is: " $res
read -p "Do you wish to continue? [y]es or [n]o: " ans
if [ $ans == 'n' ]
then
echo "Exiting the script. Have a nice day!"
break
else
continue
fi
doneСценарий работает хорошо, однако обратите внимание, что строки для приема входных данных повторяются в каждом шаблоне в нашем операторе switch.
#!/bin/bash
inputs(){
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
}
exitPrompt(){
read -p "Do you wish to continue? [y]es or [n]o: " ans
if [ $ans == 'n' ]
then
echo "Exiting the script. Have a nice day!"
break
else
continue
fi
}
while(true)
do
clear
printf "Choose from the following operations: \n"
printf "[a]Addition\n[b]Subtraction\n[c]Multiplication\n[d]Division\n"
printf "################################\n"
read -p "Your choice: " choice
case $choice in
[aA])
inputs
res=$((int1+int2))
;;
[bB])
inputs
res=$((int1-int2))
;;
[cC])
inputs
res=$((int1*int2))
;;
[dD])
inputs
res=$((int1/int2))
;;
*)
res=0
echo "wrong choice!"
esac
echo "The result is: " $res
exitPrompt
doneМы улучшили наш код, создав подразделы inputs и exitPrompt. Он работает точно так же с нашим предыдущим кодом, однако наш текущий код легче устранять, поскольку он правильно структурирован.
Передача параметров в функции
Как и в большинстве языков программирования, вы можете передавать параметры и обрабатывать эти данные в функциях в bash. В приведенном ниже коде показана процедура передачи значений в сценариях оболочки:
#!/bin/bash
myfunction(){
echo $1
echo $2
}
myfunction "Hello" "World"Обратите внимание, что в нашем примере мы добавили значения «Hello» и «World» после того, как вызвали myfunction. Эти значения передаются функции my как параметры и сохраняются в локальной переменной. Однако, в отличие от других языков, интерпретатор сохраняет переданные значения в предопределенные переменные, которые именуются в соответствии с последовательностью передачи параметров, 1 в качестве начального имени до порядка передачи. Обратите внимание, что слово «Hello» хранится в переменной 1, а значение «World» хранится в переменной 2.
Примечание. 1 и 2 в нашем примере являются локальными переменными и, следовательно, недоступны для других частей скрипта, кроме функции, в которую передаются параметры.
Например,
#!/bin/bash
myfunction(){
echo $1
echo $2
}
myfunction "Hello" "World"
echo $1
echo $2Эхо $1 и эхо $2 в последних двух строках нашего скрипта не отображаются, так как интерпретатор не распознает обе переменные, потому что они обе являются локальными для функции my.
Возврат значений из функций
Помимо создания функций и передачи им параметров, функции bash могут передавать значения локальной переменной функции в основную процедуру с помощью ключевого слова return. Затем возвращенные значения сохраняются в переменной по умолчанию $? Например, рассмотрим следующий код:
#!/bin/bash
add(){
sum=$(($1+$2))
return $sum
}
read -p "Enter an integer: " int1
read -p "Enter an integer: " int2
add $int1 $int2
echo "The result is: " $?В примере мы передаем параметры int1 и int2 в функцию добавления. Затем функция добавления обрабатывает его через строку sum=$ (($1+$2)). Затем значение переменной sum передается в основную процедуру через строку return $sum. По умолчанию значения $sum будут сохранены в переменной по умолчанию $? Наконец, строка echo \Результат:\$? печатает результат.
Note: Shell scripts can only return a single value.
В отличие от других языков программирования, сценарии оболочки не могут возвращать из функции несколько значений. Давайте посмотрим на этот пример:
#!/bin/bash
add(){
sum=$(($1+$2))
dif=$(($1-$2))
return $sum
}
read -p "Enter an integer: " int1
read -p "Enter an integer: " int2
add $int1 $int2
echo "The result is: " $?
echo "The result is: " $?Подвести итог
Давайте рассмотрим еще один пример, который использует функции, передает им параметры и возвращает значение.
#!/bin/bash
#####################
#Author: HowtoForge #
#####################
clear(){
clear
}
bin(){
bin1=$(echo "obase=2;$1"|bc)
echo $bin1
}
dec(){
dec1=$(echo "ibase=2;$1"|bc)
return $dec1
}
########Main#########
printf "Choose from the following operations:\n[1]Decimal to Binary Conversion\n"
printf "[2]Binary to Decimal Conversion\n"
read -p "Your choice: " op
case $op in
1)
read -p "Enter integer number: " int
bin $int
;;
2)
read -p "Enter binary number: " int
dec $int
echo "The decimal equivalent of $int is $?"
;;
*)
echo "Wrong Choice!"
esacВ данном примере заданный ввод преобразуется как в двоичное, так и в десятичное значение с использованием команд obase и ibase. Строка $ (echo \obase=2;$1\|bc) преобразует заданное десятичное значение в двоичное число и сохраняет его в переменной bin1. Затем мы отобразили значение $bin1 с помощью команды echo.
Note: It's better to use echo directly when converting from decimal to binary because when you return command to pass a binary value, the bash converts the binary value to decimal before returning it.
Кроме того, мы преобразовали двоичное значение в десятичное с помощью команды $ (echo \ibase=2;$1\|bc).
Вы также должны помнить, что интерпретатор способен принимать только 8-битные двоичные цифры. Если вы введете цифру, превышающую 8-битный предел, произойдет переполнение, и старший бит цифры будет отброшен.
10-битная двоичная цифра 1000001010 возвращает 10, поскольку в соответствии с правилом 8-битной оставшиеся 2 бита в правой части (старший значащий бит) будут опущены, таким образом, 1000001010 станет равным 00001010, что равно 10. Если вы хотите операцию, которая принимает двоичные цифры, превышающие 8 бит, тогда вам нужно создать код вручную.
Заключение
Bash имеет функции, очень похожие на языки программирования, чтобы предоставить пользователю множество инструментов и сделать системы Linux более мощными. В этой серии вы расширили свои знания в написании сценариев оболочки с помощью функций. Функции в сценариях оболочки для обеспечения модульности для пользователя, что упрощает устранение неполадок в сценариях и позволяет повторно использовать код.
Ссылка:
[1] Словарь английского языка American Heritage®, пятое издание. Авторские права © 2011 г., издательство Houghton Mifflin Harcourt Publishing Company. Опубликовано издательством Houghton Mifflin Harcourt Publishing Company.