Вопрос или проблема
Давайте определим эту очень маленькую bash-функцию:
function test() {
a=4
echo "Hello world"
}
Если я запущу функцию, то переменная a
примет значение 4
(что является ожидаемым результатом):
test ; echo $a
Hello world
4
Если я удалю переменную a
(или начну заново без определенной переменной a), и я передам выход функции в команду, переменная a
не будет установлена:
test | cat ; echo $a
Hello world
Почему переменная не установлена в 4
в этом случае? Могу ли я установить переменную из функции независимо от того, передаю ли я ее вывод или нет?
Спасибо.
Ответ или решение
Чтобы установить глобальную переменную из функции Bash, когда ее вывод передается в другую команду, необходимо понимать работу области видимости переменных в оболочке Bash. В данном случае, переменная, определенная внутри функции, считается локальной и не будет доступна вне ее контекста, если вывод функции перенаправляется (передается) в другую команду через пайп (|).
Объяснение проблемы
Когда вы вызываете функцию test()
без перенаправления, переменная a
устанавливается правильно, и вы можете получить к ней доступ после выполнения функции:
function test() {
a=4
echo "Hello world"
}
test ; echo $a
Вывод будет:
Hello world
4
Однако, если вы применяете пайп, как в следующем примере:
test | cat ; echo $a
Вывод будет:
Hello world
В этом случае переменная a
не будет определена вне функции, и результатом будет пустая строка. Это происходит потому, что при использовании пайпа функция test()
выполняется в отдельном подпроцессе. Таким образом, любые изменения переменных, сделанные внутри функции, будут локальными для этого процесса и не будут затрагивать родительский процесс, в котором вы выполняете команду.
Как установить глобальную переменную в контексте выполнения командами с пайпом
Если вы хотите установить глобальную переменную, которую можно использовать даже при пайпах, вы можете использовать следующие подходы.
1. Используйте process substitution
Этот метод позволяет запустить команду в подпроцессе и получить вывод, не теряя глобальные переменные.
function test() {
a=4
echo "Hello world"
}
test | { read; echo $a; }
Тем не менее, нужно понимать, что в этом случае переменная a
все равно не будет видна. Такой подход не подходит, если вам нужно получить значение переменной.
2. Используйте eval
или другие методы
Вы можете создать строку, которая присвоит значение вашей переменной и выполнить её через eval
.
function test() {
echo "a=4"
echo "Hello world"
}
eval $(test | tail -n +2) ; echo $a
Это выполнит строку, сгенерированную функцией, и переменная a
будет доступна глобально.
Заключение
Определять глобальные переменные в Bash через функции — это задача, требующая понимания как работают процессы и области видимости. Пайпы создают отдельные процессы, что делает переменные недоступными после выполнения. Использование подхода с eval
или другими орудиями может помочь вам обойти эту особенность. Если вам нужно много информации о переменных, лучше придерживаться более простых конструкций, таких как запоминание значений в файлах или использование других методов межпроцессной коммуникации по мере необходимости.