Функции в Bash
Содержание
Функции в Bash - отличный способ повторного использования кода. В этом разделе нашего учебного руководства по Bash вы узнаете, как они работают и что вы можете с ними делать.
Подумайте о функции как небольшом скрипте в скрипте. Это небольшой фрагмент кода, который вы можете вызывать несколько раз в своем скрипте. Они особенно полезны, если у вас есть определенные задачи, которые необходимо выполнить несколько раз. Вместо того, чтобы писать один и тот же код снова и снова, вы можете записать его один раз в функцию, а затем вызывать эту функцию каждый раз.
Функции
Создание функции довольно просто. Они могут быть написаны в двух разных форматах:
function_name () { <команды> }
или
function function_name { <команды> }
Несколько замечаний:
- Любой из указанных выше способов задания функции действителен. Оба действуют одинаково, и нет никаких преимуществ или недостатков для одного над другим. Это действительно личное предпочтение.
- В других языках программирования обычно передаются аргументы функции, перечисленной внутри скобок (). В Баше они есть только для украшения, и вы никогда ничего не вкладываете в них.
- Определение функции (сама фактическая функция) должно появляться в скрипте перед любыми вызовами функции.
Давайте рассмотрим простой пример:
function_example.sh
#!/bin/bash # Основная функция print_something () { echo Hello I am a function } print_something print_something
Давайте разберем это:
- Строка 4 - Мы начинаем определять функцию, указывая ей имя.
- Строка 5 - В фигурных скобках у нас может быть столько команд, сколько нам нравится.
- Строки 8 и 9. После того, как функция определена, мы можем назвать ее столько раз, сколько нам нравится, и она выполнит эти команды.
Передача аргументов
Часто бывает так, что мы хотели бы, чтобы функция обрабатывала некоторые данные для нас. Мы можем отправлять данные в функцию аналогично передаче аргументов командной строки скрипту. Мы приводим аргументы непосредственно после имени функции. В рамках функции они доступны как $1, $2 и т. д.
arguments_example.sh
#!/bin/bash # Передача аргументов функции print_something () { echo Hello $1 } print_something Mars print_something Jupiter
Возвращаемые значения
Большинство других языков программирования имеют концепцию возвращаемого значения для функций, средство для функции отправки данных обратно в исходное местоположение вызова. Функции Bash не позволяют нам это делать. Однако они позволяют установить статус возврата. Аналогично тому, как программа или команда выходит с статусом выхода, который указывает, было ли это выполнено или нет. Мы используем ключевое слово return, чтобы указать статус возврата.
return_status_example.sh
#!/bin/bash # Установка статуса возврата для функции print_something () { echo Hello $1 return 5 } print_something Mars print_something Jupiter echo The previous function has a return value of $?
Давайте разберем его
- Строка 6 - Статус возврата не обязательно должен быть жестко запрограммирован. Это может быть переменная
- Строка 11 - Помните, что переменная $? содержит статус возврата ранее выполняемой команды или функции.
Обычно статус возврата 0 указывает, что все прошло успешно. Значение, отличное от нуля, указывает на возникшую ошибку.
Если все, что вы хотите сделать, это вернуть число (например, результат вычисления), то вы можете рассмотреть возможность использования возвращаемого статуса для достижения этого. Это не намеренная цель, но она будет работать.
Один из способов обойти это - использовать Command Substitution и заставить функцию распечатать результат (и только результат).
return_hack.sh
#!/bin/bash # Установка возвращаемого значения функции lines_in_file () { cat $1 | wc -l } num_lines=$( lines_in_file $1 ) echo The file $1 has $num_lines lines in it.
Давайте разберем это:
- Строка 5 - эта команда будет печатать количество строк в файле, на которое ссылается $ 1.
- Строка 8 - Мы используем подстановку команд, чтобы взять то, что обычно печатается на экране, и назначать ее переменной num_lines
Просто будьте осторожны, если вы примете такой подход, как если бы вы не вызывали функцию с подстановкой команды, тогда она выводит результат на экран. Иногда это нормально, потому что это то, что вы хотите. В других случаях это может быть нежелательным.
Область переменных
Область действия относится к тому, какие части скрипта могут видеть, какие переменные. По умолчанию переменная является глобальной . Это означает, что это видно повсюду в скрипте. Мы также можем создать переменную как локальную переменную. Когда мы создаем локальную переменную внутри функции, она видна только внутри этой функции. Для этого мы используем ключевое слово local перед переменной в первый раз, когда мы устанавливаем его значение.
local var_name = <var_value>
Обычно считается хорошей практикой использовать локальные переменные внутри функций, чтобы сохранить все внутри функции. Таким образом, переменные более безопасны из-за непреднамеренного изменения другой части скрипта, которая имеет переменную с тем же именем (или наоборот).
local_variables.sh
#!/bin/bash # Experimenting with variable scope var_change () { local var1='local 1' echo Inside function: var1 is $var1 : var2 is $var2 var1='changed again' var2='2 changed again' } var1='global 1' var2='global 2' echo Before function call: var1 is $var1 : var2 is $var2 var_change echo After function call: var1 is $var1 : var2 is $var2
Всегда используйте локальные переменные внутри функций. Используйте глобальные переменные как последнее средство и подумайте, есть ли лучший способ сделать это, прежде чем использовать их.
Сфера может иногда быть трудной для того, чтобы сначала опустить голову. Если это кажется немного запутанным, лучшим подходом является создание сценария Bash, аналогичного приведенному выше, и его несколько раз настраивать и изменять переменные в разных местах, а затем наблюдать за поведением при его запуске.
Переопределение команд
Можно назвать функцию как то же имя, что и команда, которую вы обычно используете в командной строке. Это позволяет создать обертку. например. Может быть, каждый раз, когда мы вызываем команду ls в нашем скрипте, мы действительно хотим, чтобы ls -lh . Мы могли бы сделать следующее:
override.sh
#!/bin/bash # Создайте оболочку вокруг команды ls ls () { command ls -lh } ls
Давайте разберем это:
- Строка 5 - Когда мы имеем функцию с тем же именем, что и команда , нам нужно поместить ключевое слово команды перед именем , когда мы хотим , чтобы команда , в отличие от функции , как функция обычно имеет приоритет.
В приведенном выше примере, если бы мы не поставили ключевую команду перед ls в строке 5, мы закончили бы бесконечный цикл. Несмотря на то, что мы находимся внутри функции ls, когда мы вызываем ls, она вызвала бы другой экземпляр функции ls, который, в свою очередь, сделал бы то же самое и так далее.
Легко забыть ключевое слово команды и заканчиваться бесконечным циклом. Если вы столкнулись с этим, вы можете отменить запуск сценария, одновременно нажав клавиши CTRL c на клавиатуре. CTRL c - отличный способ отменить ваш скрипт (или программу) всякий раз, когда вы попадаете в проблему в командной строке.
Дизайн
Создание функций в ваших сценариях Bash очень просто. Однако создание хороших функций, которые упрощают запись и обслуживание ваших сценариев, требует времени и опыта. Как и в большинстве случаев с компьютерами, когда вы достигаете такого уровня сложности, вы сможете достичь желаемого результата несколькими способами. Некоторые из них будут лучше других, поэтому найдите время, чтобы подумать о разных способах написания кода, и каким образом может быть лучше.
Иногда лучше - это наименьшие строки кода, иногда лучше всего легче изменить позже, если изменения будут изменены. Иногда лучше подход, который наименее подвержен ошибкам.
Если конкретная задача должна выполняться несколько раз, то это хороший кандидат для размещения внутри функции.
Иногда полезно размещать вспомогательные задачи внутри функций, чтобы они были логически отделены от основной части скрипта. Общим примером является проверка ввода (например, обеспечение того, что указанный файл существует и доступен для чтения).
Функция наиболее удобна при выполнении одной задачи и только одной задачи. Вместо того, чтобы иметь большую функцию, рассмотрите возможность разбить ее на несколько функций и разбить задачу.
Однако вам нужно найти правильный баланс. Если функции слишком велики и требуют слишком большой обработки, то вы не получите полной выгоды. Если вы разделите слишком много функций, ваш код может легко расти и стать глупым. С опытом вы найдете это сладкое пятно посередине.
Часть 6. Циклы for, while, until в Bash