Comment puis-je affecter la sortie d'une fonction à une variable à l'aide de bash?

97

J'ai une fonction bash qui produit une sortie:

function scan {
  echo "output"
}

Comment puis-je affecter cette sortie à une variable?

c'est à dire. VAR = scan (bien sûr, cela ne fonctionne pas - cela rend VAR égal à la chaîne "scan")

Brent
la source
1
En relation: stackoverflow.com/q/3236871/435605
AlikElzin-kilaka

Réponses:

145
VAR=$(scan)

Exactement de la même manière que pour les programmes.

Robert Obryk
la source
3
J'ai découvert que les nouvelles lignes étaient supprimées quand j'ai fait "echo $ VAR". Si à la place j'ai cité $ VAR, il a conservé les nouvelles lignes.
Brent
2
Ce n'est pas vrai à 100%. La substitution de commande supprime toujours les nouvelles lignes de fin.
TheBonsai
7
Cela crée un sous-shell; y a-t-il un moyen de le faire dans le même shell?
Expiation limitée
24

Vous pouvez utiliser les fonctions bash dans les commandes / pipelines comme vous utiliseriez autrement des programmes réguliers. Les fonctions sont également disponibles pour les sous-shells et de manière transitoire, Command Substitution:

VAR=$(scan)

C'est le moyen le plus simple d'obtenir le résultat souhaité dans la plupart des cas. Je décrirai des cas particuliers ci-dessous.

Préserver les nouvelles lignes de fin:

L'un des effets secondaires (généralement utiles) de la substitution de commandes est qu'elle supprime n'importe quel nombre de nouvelles lignes de fin. Si l'on souhaite conserver les retours à la ligne de fin, on peut ajouter un caractère factice à la sortie du sous-shell, puis le dépouiller avec l'expansion des paramètres.

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}---"

impressions (3 retours à la ligne conservés):

output


---

Utiliser un paramètre de sortie: éviter le sous-shell (et préserver les nouvelles lignes)

Si ce que la fonction essaie de réaliser est de «retourner» une chaîne dans une variable, avec bash v4.3 et plus, on peut utiliser ce qu'on appelle a nameref. Namerefs permet à une fonction de prendre le nom d'un ou de plusieurs paramètres de sortie de variables. Vous pouvez assigner des choses à une variable nameref, et c'est comme si vous changiez la variable vers laquelle elle «pointe / références».

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}==="

imprime:

output

===

Ce formulaire présente quelques avantages. À savoir, il permet à votre fonction de modifier l'environnement de l'appelant sans utiliser de variables globales partout.

Remarque: l'utilisation de namerefs peut grandement améliorer les performances de votre programme si vos fonctions reposent fortement sur les fonctions intégrées de bash, car cela évite la création d'un sous-shell qui est jeté juste après. Cela a généralement plus de sens pour les petites fonctions souvent réutilisées, par exemple les fonctions se terminant parecho "$returnstring"

Ceci est pertinent. https://stackoverflow.com/a/38997681/5556676

init_js
la source
0

Je pense que init_js devrait utiliser declare au lieu 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
la source
le localbuiltin acceptera toutes les options que le declarebuiltin acceptera. à partir d'un test rapide, il semble également que la declare -nportée d'une fonction donne également la portée locale de la variable. il semble qu'ils soient interchangeables ici.
init_js