¿Cómo hacer que `local` capture el código de salida?

11

En mi proyecto tengo el siguiente fragmento:

local output="$(bash "${1##*/}")"
echo "$?"

Esto siempre imprime cero debido a que local, sin embargo, la eliminación localhace que la $?variable se comporte correctamente: lo que supone asumir el código de salida de la subshell.

Mi pregunta es: ¿cómo puedo mantener esta variable local y al mismo tiempo capturar el valor de salida?

Halcón supremo
fuente
1
shellcheckno solo detectará este problema, sino que sugerirá la solución en unix.stackexchange.com/a/281749/24718 .
Waleed Khan

Respuestas:

16
#!/bin/bash
thing() {
   local foo=$(asjkdh) ret="$?"
   echo "$ret"
}

Esto hará eco 127, el código de error correcto para "comando no encontrado".

Puede usar localpara definir más de una variable. Así que también creo la variable local RETpara capturar el código de salida de la subshell antes de tener localéxito y establece $?en cero.

DopeGhoti
fuente
¿Se garantiza que bashevalúa esta expresión de izquierda a derecha?
Max Ried
Hasta donde yo sé, las asignaciones variables están en orden, de izquierda a derecha en este contexto, sí.
DopeGhoti
@MaxRied el hecho de que esto funciona de manera confiable parece indicar que sí, lo es. Sin embargo, no puedo encontrar información sobre esto ni en POSIX ni en bashel manual de referencia.
gato
10
Por otro lado, usar nombres de variables en mayúsculas es una mala forma. Consulte la especificación de la variable de entorno POSIX en pubs.opengroup.org/onlinepubs/009695399/basedefs/… , que describe los nombres en mayúsculas como reservados para variables con significado para el shell o el sistema y nombres con al menos un carácter en minúscula reservado para el uso definido por la aplicación, teniendo en cuenta que las variables de shell y las variables de entorno comparten un espacio de nombres (ya que, en caso de colisiones, la asignación a la primera puede anular la segunda).
Charles Duffy
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
terdon
27

Declare la variable local antes de asignarla:

thing() {
  local output
  output="$(bash "${1##*/}")"
  echo "$?"
}

En mi opinión, esto también es más legible que establecer una RETvariable adicional . YMMV en eso, pero funciona exactamente como cabría esperar.

Comodín
fuente
2
Esto es mucho mejor que usar una variable separada, como debería ser obvio si desea verificar el código de retorno de múltiples tareas: simplemente local var1 var2 ...y Bob es su tío.
l0b0
@ l0b0 Bob es mi tío. : D
gato