A solução que você está mostrando acima é uma que é de propósito geral e abrange muitos casos. A menos que você saiba que tem um problema, você pode querer adotar uma postura YAGNI (Você não vai precisar disso) e apenas redirecionar suas linhas selecionadas para / dev / tty.
Se você quiser evitar isso, então você precisa entender o malabarismo do descritor de arquivos (fd) que está acontecendo.
O 3>&1
está copiando o stdout do contexto de chamada para uma "célula de retenção" para que a função possa ser enviada para o stdout do contexto de chamada. Nesse caso, é / dev / tty. Lembre-se, a função será chamada com stdout pertencente a um subshell para a substituição $ {}.
O exec 4>&1
cria uma cópia do fd1, que é o stdout da função. O fd4 está sendo usado como uma célula de retenção para o stdout com o qual a função começa. O >&3
está definindo o stdout da função / subshell para o stdout do chamador. Assim, toda a saída irá para o stdoout do chamador. UNTIL, o final em que o >&4-
move o stdout salvo de volta para o início, permitindo que o último echo "$s"
esteja no stdout da função (e subshell).
Ufa!
Os >&3
e >&4-
também podem ser escritos com mais clareza como 1>&3
e 1>&4-
.
A seção manual bash
em REDIRECTION, explica todos os detalhes de & gory & gory; nomenclatura. Fiquei satisfeito e surpreso ao ver que é realmente possível usar formulários {name} para alterar os números para palavras.
"Cada redirecionamento que pode ser precedido por um número de descritor de arquivo pode ser precedido por uma palavra da forma {varname}. Nesse caso, para cada operador de redirecionamento, exceto > & - & < & -, o shell alocará um descritor de arquivo maior que 10 e o atribuirá a varname. Se > & - ou < & - for precedido por {varname}, o valor de varname definirá o descritor de arquivo para fechar. "
Eu não testei isso, mas sugere que você poderia codificar isso como:
#!/bin/bash
exec {caller_stdio}>&1
returnString() {
exec {func_stdio}>&1 1>&{caller_stdio}
local s=$1
s=${s:="some default string"}
echo "writing to stdout"
echo "writing to stderr" >&2
exec 1>&{func_stdio}-
echo "$s"
}
my_string=$(returnString "$*")
echo "my_string: [$my_string]"
Espero que isso ajude.