Bash скриптинг echo локально в функции

Вопрос или проблема

В скриптах 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, которые обеспечивают более высокоуровневые структуры обработки ошибок и возврата значений.

Оцените материал
Добавить комментарий

Капча загружается...