Come posso assegnare l'output di una funzione a una variabile usando bash?


Risposte:


145
VAR=$(scan)

Esattamente allo stesso modo dei programmi.


3
Ho scoperto che le nuove righe venivano rimosse quando ho fatto "echo $ VAR". Se invece ho citato $ VAR, ha conservato le nuove righe.
Brent

2
Non è corretto al 100%. La sostituzione del comando rimuove sempre le nuove righe finali.
TheBonsai

7
Questo crea una subshell; c'è un modo per farlo nella stessa shell?
Espiazione limitata

24

Puoi usare le funzioni bash nei comandi / pipeline come faresti altrimenti con programmi regolari. Le funzioni sono disponibili anche per subshell e transitivamente, Command Substitution:

VAR=$(scan)

È il modo più diretto per ottenere il risultato desiderato nella maggior parte dei casi. Descriverò casi speciali di seguito.

Preservare le nuove righe finali:

Uno degli effetti collaterali (solitamente utili) della sostituzione del comando è che eliminerà qualsiasi numero di nuove righe finali. Se si desidera conservare le nuove righe finali, è possibile aggiungere un carattere fittizio all'output della subshell e successivamente rimuoverlo con l'espansione dei parametri.

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

stampe (3 newline mantenute):

output


---

Usa un parametro di output: evitare la subshell (e preservare le nuove righe)

Se ciò che la funzione cerca di ottenere è "restituire" una stringa in una variabile, con bash v4.3 e versioni successive, si può usare ciò che viene chiamato a nameref. Namerefs consente a una funzione di prendere il nome di uno o più parametri di output delle variabili. Puoi assegnare cose a una variabile nameref, ed è come se avessi cambiato la variabile che "punta a / fa riferimento".

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

stampe:

output

===

Questa forma presenta alcuni vantaggi. Vale a dire, consente alla funzione di modificare l'ambiente del chiamante senza utilizzare variabili globali ovunque.

Nota: l'uso di namerefs può migliorare notevolmente le prestazioni del tuo programma se le tue funzioni fanno molto affidamento sui builtin bash, perché evita la creazione di una subshell che viene gettata via subito dopo. Questo generalmente ha più senso per piccole funzioni riutilizzate spesso, ad esempio funzioni che terminano conecho "$returnstring"

Questo è rilevante. https://stackoverflow.com/a/38997681/5556676


0

Penso che init_js dovrebbe usare declare invece di local!

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

il localbuiltin accetterà tutte le opzioni che il declarebuiltin accetterà. da un rapido test, sembra anche che declare -nin uno scope di funzione fornisca anche l'ambito locale della variabile. sembra che siano intercambiabili qui.
init_js
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.