¿Cómo puedo asignar la salida de una función a una variable usando bash?

97

Tengo una función bash que produce algunos resultados:

function scan {
  echo "output"
}

¿Cómo puedo asignar esta salida a una variable?

es decir. VAR = escanear (por supuesto, esto no funciona, hace que VAR sea igual a la cadena "escanear")

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

Respuestas:

145
VAR=$(scan)

Exactamente de la misma forma que para los programas.

Robert Obryk
fuente
3
Descubrí que las nuevas líneas se estaban eliminando cuando hice "echo $ VAR". Si en cambio cité $ VAR, preservó las nuevas líneas.
Brent
2
Eso no es 100% correcto. La sustitución de comandos siempre elimina las nuevas líneas finales.
TheBonsai
7
Esto crea una subcapa; ¿Hay alguna forma de hacerlo en el mismo caparazón?
Expiación limitada
24

Puede usar funciones bash en comandos / canalizaciones como lo haría con programas normales. Las funciones también están disponibles para subcapas y de forma transitiva, sustitución de comandos:

VAR=$(scan)

Es la forma más sencilla de conseguir el resultado deseado en la mayoría de los casos. A continuación, describiré casos especiales.

Conservación de las nuevas líneas finales:

Uno de los efectos secundarios (generalmente útiles) de la sustitución de comandos es que eliminará cualquier número de nuevas líneas finales. Si se desea conservar las nuevas líneas finales, se puede agregar un carácter ficticio a la salida de la subcapa y posteriormente eliminarlo con la expansión de parámetros.

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

impresiones (se mantienen 3 líneas nuevas):

output


---

Utilice un parámetro de salida: evitar la subcapa (y preservar las líneas nuevas)

Si lo que la función intenta lograr es "devolver" una cadena a una variable, con bash v4.3 y versiones posteriores, se puede usar lo que se llama a nameref. Namerefs permite que una función tome el nombre de una o más variables de parámetros de salida. Puede asignar cosas a una variable nameref, y es como si cambiara la variable a la que 'apunta / hace 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}==="

huellas dactilares:

output

===

Esta forma tiene algunas ventajas. Es decir, permite que su función modifique el entorno de la persona que llama sin utilizar variables globales en todas partes.

Nota: el uso de namerefs puede mejorar el rendimiento de su programa en gran medida si sus funciones dependen en gran medida de las incorporaciones de bash, porque evita la creación de una subcapa que se desecha justo después. Esto generalmente tiene más sentido para funciones pequeñas que se reutilizan con frecuencia, por ejemplo, funciones que terminan enecho "$returnstring"

Esto es relevante. https://stackoverflow.com/a/38997681/5556676

init_js
fuente
0

¡Creo que init_js debería usar declare en lugar 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
fuente
el localincorporado aceptará cualquier opción que declareacepte el incorporado. a partir de una prueba rápida, también parece que declare -nen el ámbito de una función también se da ámbito local a la variable. parece que son intercambiables aquí.
init_js