Вопрос или проблема
В скриптах bash я стараюсь сохранять переменные локальными для функций, где это возможно, а затем передавать то, что мне нужно, из функций, как показано ниже
#!/bin/bash
function FUNCTION() {
local LOCAL="value"
echo "$LOCAL" # вернуть эту переменную
}
GLOBAL=$(FUNCTION)
echo "$GLOBAL"
Но возможно ли сделать это, включая собственные сообщения функции, так что если функция имеет свои собственные сообщения для вывода, мне не нужно ловить их в переменной
#!/bin/bash
function FUNCTION() {
local LOCAL="value"
echo "$LOCAL" # вернуть эту переменную
echo "Эта функция завершена" # не возвращать эту переменную
}
GLOBAL=$(FUNCTION)
echo "$GLOBAL" # должно выдать только 'value'
Все, что выводится функцией, можно захватить, если вы захватите нужный поток вывода. Поэтому самый простой способ напечатать что-то и сохранить некоторый другой вывод — это перенаправить избыточный вывод в стандартный поток ошибок:
function FUNCTION() {
local LOCAL="value"
echo "$LOCAL"
echo "Эта функция завершена" >&2
}
Еще одна возможность — записывать в файл, а не выводить сообщения лога напрямую, например, используя что-то вроде этого:
log() {
printf '%s\n' "$@" > my.log
}
Тем не менее, функции Bash не могут возвращать переменные. Единственное фактическое “возвратное” значение — это код завершения. По этой причине (и многие другие), если вы хотите надежного логирования, возвратов значений, обработки исключений и многого другого, вам стоит использовать другой язык, например, Python, Ruby или Java.
Вы можете выводить информационные сообщения в стандартный поток ошибок:
function FUNCTION() {
local LOCAL="value"
echo "$LOCAL" # вернуть эту переменную
echo "Эта функция завершена" > /dev/stderr # выводится на экран
}
Некоторые другие предложения можно найти в этой статье журнала Linux: используйте глобальные переменные (которые, как вы упомянули, не предпочитаете), или передавайте имя переменной, в которую нужно вернуть результат.
Вы можете обойти stderr
, добавив новый дескриптор файла.
$ cat hello
#!/bin/bash
exec 3>&1
function f () {
echo hello >&3
echo world
}
x=$(f)
echo "'$x'"
$ bash hello
hello
'world'
$ █
Тем не менее, я не эксперт в использовании exec
и перенаправлений.
Ответ или решение
Локальные переменные и вывод сообщений в Bash
Bash — это мощный инструмент для скриптинга, который предоставляет разработчикам возможность использовать функции и локальные переменные для организации и управления кодом. Вам может быть интересно, как можно эффективно использовать функции в Bash, чтобы вернуть значения и одновременно выводить сообщения, не захватывая их в переменные. Давайте разберем это подробнее.
Локальные переменные в функциях
При написании Bash-скриптов важно локализовать переменные в пределах функции для предотвращения их воздействия на глобальный контекст. Например:
#!/bin/bash
function FUNCTION() {
local LOCAL="value" # Локальная переменная
echo "$LOCAL" # Возвращаем значение локальной переменной
}
GLOBAL=$(FUNCTION) # Захватываем возвращаемое значение
echo "$GLOBAL" # Вывод: value
В приведенном примере, функция FUNCTION
возвращает значение локальной переменной LOCAL
. Однако, если в той же функции вы хотите вывести другие сообщения, вы столкнетесь с проблемой, так как эти сообщения тоже будут записаны в переменную GLOBAL
.
Вывод сообщений в стандартный поток ошибок
Одно из простых решений — выводить избыточные сообщения на стандартный поток ошибок (stderr) с помощью перенаправления:
function FUNCTION() {
local LOCAL="value"
echo "$LOCAL" # Возвращаем значение
echo "Этот процесс завершен" >&2 # Сообщение выведено в stderr
}
Теперь, вызвав FUNCTION
, вы получите локальную переменную value
в GLOBAL
, в то время как сообщение об завершении будет выведено на экран:
GLOBAL=$(FUNCTION) # Извлечение значения
echo "$GLOBAL" # Вывод: value
Сообщение о завершении будет видимо, но не попадает в переменную GLOBAL
.
Использование дополнительных файловых дескрипторов
Еще одним интересным подходом является использование дополнительных файловых дескрипторов. Это позволяет вам точно контролировать, куда будет направлен вывод:
#!/bin/bash
exec 3>&1 # Открываем новый файловый дескриптор, указывающий на стандартный выход
function FUNCTION() {
echo "Привет из функции" >&3 # Сообщение выводится через файловый дескриптор 3
echo "Этот процесс завершен"
}
GLOBAL=$(FUNCTION) # Получаем значение
echo "'$GLOBAL'" # Вывод: 'Этот процесс завершен'
В этом примере первое сообщение будет выведено в стандартный выход, а второе — на стандартный выход (stdout, т.е. в переменную GLOBAL
).
Логирование сообщений в файл
Еще один вариант — использование функции для логирования сообщений в файл. Это позволит вам отдельно записывать логи и возвращаемые значения:
log() {
printf '%s\n' "$@" >> my.log # Запись логов в файл
}
function FUNCTION() {
local LOCAL="value"
echo "$LOCAL" # Возвращаем значение
log "Этот процесс завершен" # Логируем сообщение
}
Таким образом, сообщения логируются в файл my.log
, а возвращаемое значение остается доступным для других операций.
Заключение
Bash предоставляет множество возможностей для работы с функциями, локальными переменными и выводами. Выбор метода зависит от ваших конкретных требований. Используйте перенаправления, дополнительные файловые дескрипторы или файлы для логирования в зависимости от контекста вашего скрипта.
Если ваши задачи становятся более сложными и требуют расширенной обработки данных, стоит рассмотреть возможность использования других языков, таких как Python или Ruby, которые обеспечивают более высокоуровневые структуры обработки ошибок и возврата значений.