Если вы программист, который время от времени работает со сценарием bash, вас может беспокоить, что функция bash не возвращает ничего, кроме целого числа от 0 до 255.
Давайте представим, написали ли вы функцию, которая возвращает строку, например:
#!/bin/bash function hello() { return "Hello $1" } echo $(hello world)
Оператор return не работает:
The return statement doesn’t work: test.sh: line 5: return: Hello world: numeric argument required
Это связано с тем, что ключевое слово return в bash предназначено для функции, возвращающей статус выхода. Но как вернуть что-нибудь осмысленное из функции bash? Обычный способ возврата вещей с помощью функций — это STDOUT (стандартный вывод):
#!/bin/bash function hello() { echo "Hello $1" } echo $(hello world)
Что бы сработало. Но рассмотрите эти:
- Как бы вы вернули несколько переменных?
- Как бы вы вернули массив строк, некоторые из которых содержат пробел?
- Как бы вы вернули несколько переменных, одна из которых является массивом, который может содержать пробелы?
Конечно, это второстепенный случай. Большинство людей возразят: «Какого черта мне это нужно?» И они абсолютно правы. Но предположим, что мир вот-вот взорвется, если вы не сможете сделать это с помощью функции bash, что вы могли бы сделать?
В ПОРЯДКЕ. Я знаю, что вы можете возиться с глобальными переменными. Но все мы знаем, что функция, имеющая побочный эффект для глобальной переменной с фиксированным именем, воняет. И даже если бы ты сделал это, когда нужно, внутри тебя умирает частичка…
Так что ты можешь сделать?
(Барабанный бой…)
Входит объявлять.
Команда bash «declare» (или ее синонимы «typeset») — это встроенная команда bash, позволяющая изменять свойства переменных. Нас интересуют параметры -n
:
-n
Дайте каждому имени атрибут nameref, сделав его ссылкой имени на другую переменную. Эта другая переменная определяется значением имени. Все ссылки, присвоения и изменения атрибутов имени, за исключением тех, которые используют или изменяют сам атрибут -n, выполняются для переменной, на которую ссылается значение имени. Атрибут nameref нельзя применять к переменным массива.
По сути, его можно использовать для передачи по ссылке:
#!/bin/bash function hello { declare -n OUTPUT=$2 OUTPUT="Hello $1" } hello "world" MSG && echo "$MSG"
Это создаст локальную переменную $OUTPUT
в качестве ссылки на переменную $MSG
(предоставляется здесь для 2-го аргумента $2
). Переменная $OUTPUT
существует только в локальной области видимости функции. Таким образом, никакая глобальная переменная не разбрасывается.
Поскольку здесь мы не используем ни return
, ни STDOUT, мы все равно можем использовать return для обработки ошибок. Такие как:
#!/bin/bash function find_id_in_restful_api { local API_TOKEN=$1 local SEARCH=$2 declare -n RETURN_ID=$3 local RESPONSE=$(curl \ -X POST \ -H "Authorization: token $API_TOKEN" \ -H "Accept: application/json" \ -d "{\"search\": \"$SEARCH\"}" \ "https://api.foobar.com/someEntity") local ID=$(some_cli_json_parser $RESPONSE) if [ -z "$ID" ]; then # Oh no. The exepcted id field is not here. Signal error return 1 else RETURN_ID=$1 return 0 fi } if find_id_in_restful_api "some token" "some search term" ID; then echo "ID found! $ID" # Do some operation with $ID # ... # ... else echo "Error: ID not found!" exit 1 fi
Аккуратно, верно?
Скажите мне, что вы думаете в комментариях.