Como posso atribuir a saída de uma função a uma variável usando o bash?

100

Tenho uma função bash que produz alguma saída:

function scan {
  echo "output"
}

Como posso atribuir essa saída a uma variável?

ie. VAR = scan (claro que isso não funciona - torna VAR igual à string "scan")

Brent
fonte
1
Relacionado: stackoverflow.com/q/3236871/435605
AlikElzin-kilaka

Respostas:

150
VAR=$(scan)

Exatamente da mesma forma que nos programas.

Robert Obryk
fonte
3
Descobri que as novas linhas estavam sendo removidas quando fiz "eco $ VAR". Se, em vez disso, citei $ VAR, ele preservou as novas linhas.
Brent
2
Isso não está 100% certo. A substituição de comando sempre remove novas linhas finais.
TheBonsai
8
Isso cria um subshell; existe alguma maneira de fazer isso no mesmo shell?
lmat - Reintegração de Monica
24

Você pode usar funções bash em comandos / pipelines da mesma forma que usaria programas normais. As funções também estão disponíveis para subshells e transitivamente, Substituição de Comando:

VAR=$(scan)

É a maneira direta de obter o resultado desejado na maioria dos casos. Vou delinear casos especiais abaixo.

Preservando Newlines à direita:

Um dos efeitos colaterais (geralmente úteis) da Substituição de Comando é que ela removerá qualquer número de novas linhas finais. Se alguém deseja preservar as novas linhas finais, pode anexar um caractere fictício à saída do subshell e, subsequentemente, removê-lo com a expansão do parâmetro.

function scan2 () {
    local nl=$'\x0a';  # that's just \n
    echo "output${nl}${nl}" # 2 in the string + 1 by echo
}

# append a character to the total output.
# and strip it with %% parameter expansion.
VAR=$(scan2; echo "x"); VAR="${VAR%%x}"

echo "${VAR}---"

impressões (3 novas linhas mantidas):

output


---

Use um parâmetro de saída: evitando o subshell (e preservando novas linhas)

Se o que a função tenta alcançar é "retornar" uma string em uma variável, com bash v4.3 e superior, pode-se usar o que é chamado de a nameref. Namerefs permite que uma função receba o nome de um ou mais parâmetros de saída de variáveis. Você pode atribuir coisas a uma variável nameref, e é como se você alterasse a variável para a qual ela 'aponta / referencia'.

function scan3() {
    local -n outvar=$1    # -n makes it a nameref.
    local nl=$'\x0a'
    outvar="output${nl}${nl}"  # two total. quotes preserve newlines
}

VAR="some prior value which will get overwritten"

# you pass the name of the variable. VAR will be modified.
scan3 VAR

# newlines are also preserved.
echo "${VAR}==="

estampas:

output

===

Este formulário tem algumas vantagens. Ou seja, ele permite que sua função modifique o ambiente do chamador sem usar variáveis ​​globais em todos os lugares.

Nota: o uso de namerefs pode melhorar muito o desempenho de seu programa se suas funções dependerem muito de bash builtins, porque evita a criação de um subshell que é descartado logo depois. Isso geralmente faz mais sentido para pequenas funções reutilizadas com frequência, por exemplo, funções que terminam emecho "$returnstring"

Isso é relevante. https://stackoverflow.com/a/38997681/5556676

init_js
fonte
0

Acho que init_js deve usar declare em vez de local!

function scan3() {
    declare -n outvar=$1    # -n makes it a nameref.
    local nl=$'\x0a'
    outvar="output${nl}${nl}"  # two total. quotes preserve newlines
}
Hamid Reza Hasani
fonte
o localintegrado aceitará todas as opções que o declareintegrado aceitar. a partir de um teste rápido, também parece que declare -nem um escopo de função também dá o escopo local variável. parece que eles são intercambiáveis ​​aqui.
init_js