¿Es posible mantener $?
inalterado el último estado de salida del comando ( ) después de una prueba?
Por ejemplo, me gustaría hacer:
command -p sudo ...
[ $? -ne 1 ] && exit $?
El último exit $?
debería devolver el estado de salida de sudo, pero en su lugar siempre regresa 0
(el código de salida de la prueba).
¿Es posible hacer eso sin una variable temporal?
Otro ejemplo para aclarar más:
spd-say "$@"
[ $? -ne 127 ] && exit $?
En este caso, quiero salir solo si se encuentra el primer comando (código de salida! = 127
). Y quiero salir con el spd-say
código de salida real (puede que no lo sea
0
).
EDITAR: Olvidé mencionar que prefiero una solución de queja POSIX para una mejor portabilidad.
Utilizo esta construcción en scripts donde quiero proporcionar alternativas para el mismo comando. Por ejemplo, vea mi script crc32 .
El problema con las variables temporales es que podrían sombrear otras variables, y para evitar que debas usar nombres largos, lo que no es bueno para la legibilidad del código.
fuente
if ! command -p sudo; then exit; fi
que tendría los mismos resultados para su ejemplo.[ $? -ne 127 ] && exit $?
)sudo
comando tiene éxito (es decir, sisudo
sale con el estado 0). Pero, en su código, el script sigue ejecutándose (no sale) sisudo
tiene éxitocommand
y nosudo
en absoluto. Eso es lo que significa que quiero salir solo si se encuentra el primer comando (código de salida! = 127) y es un retorno especificado paracommand
cuando no se encuentra el comando que invoca. Supongo que el problema es que invocarsudo
como parte de la prueba permitesudo
aplastar el retornocommand
en primer lugar y así sesgar la prueba.Respuestas:
$_
trabajará en (al menos) interactivadash
,bash
,zsh
,ksh
(aunque aparentemente no en una sentencia condicional conforme a lo solicitado) ymksh
conchas. De ellos, que yo sepa, solobash
yzsh
también lo completará en un shell con script. No es un parámetro POSIX, pero es bastante portátil para cualquier shell moderno e interactivo.Para una solución más portátil, puede hacer:
Lo que básicamente le permite expandir el valor inicial
$?
a la cola del script antes de probar su valor en su cabeza.Pero de todos modos, dado que parece estar probando si el comando
sudo
se puede encontrar o no en la cadena de-p
ruta portátil incorporada del shellcommand
, creo que podría ir un poco más directamente. Además, para ser claros,command
no probará la ubicación de ningún argumento parasudo
, por lo que es solosudo
, y nada de lo que invoca, lo que es relevante para ese valor de retorno.Y de todos modos, si eso es lo que estás tratando de hacer:
... funcionaría bien como prueba sin ninguna posibilidad de que los errores en las
sudo
ejecuciones de comandos regresen de tal manera que puedan sesgar los resultados de su prueba.fuente
Hay varias opciones para manejar el estado de salida de manera confiable sin sobrecarga, dependiendo de los requisitos reales.
Puede guardar el estado de salida utilizando una variable:
Puede verificar directamente el éxito o el fracaso:
O use una
case
construcción para diferenciar el estado de salida:con el caso especial que se hace en la pregunta:
Todas esas opciones tienen la ventaja de que se ajustan al estándar POSIX.
(Nota: para la ilustración, utilicé los
echo
comandos anteriores; reemplácelos porexit
declaraciones apropiadas para que coincidan con la función solicitada).fuente
("$(get_errnos)")
es una adición artificial de una sustitución de comando en la que se solicitan comparaciones con códigos de error reales en la pregunta, 2.) En el estándar está claro qué cambia$?
(y, por lo tanto, qué no lo cambia), y 3.) allí no hay efectos secundarios con esa construcción (a menos que, como lo hiciste, los introduzcas innecesariamente). - OTOH, ya que te importa, la otra respuesta que prefieres es claramente no estándar.$(get_errnos)
código artificial a cualquier otra solución (( exit 42 ); test "$(get_errnos)" -ne $? && echo $_
), tampoco funcionan. (Prefirió incluir mi solución estándar en crédito erróneo, no los otros hacks no estándar .) - Por supuesto, puede agregar código arbitrario a cualquier respuesta y estropearlo. - Y WRT al cambio de$?
; solo porque no puedas encontrarlo no significa que no sea cierto. (Ya proporcioné en nuestras discusiones incluso las palabras clave para buscar en POSIX.)zsh
(primero mencionado solo; luego agregaste tambiéndash
) que creo que debe haber un error allí, dado que elcase
estado de salida y la configuración de$?
parece estar bien definido en POSIX. - Y también aquí, de nuevo, aplica doble rasero; el otro truco, por ejemplo, no es estándar, ni funciona de manera confiable en otros shells estándar (por ejemplo, no enksh
). - Mis propuestas son estándar y funcionanbash
(utilizadas principalmente en Linux) yksh
(el shell predominante en Unixes comerciales).Uso
$_
, que se expande al último argumento del comando anterior.fuente
$?
y$_
. En mi humilde opinión, es mejor seguir un método consistente que funciona en otros casos (y también puede ayudar con la legibilidad del código).case
patrones , el único lugar que importaría en teoría (pero no en la pregunta dada), es un caso construido. - En cualquier caso, la sustitución de su comando de shell propagaría el resultado del comando incrustado, por lo general, otras expansiones no afectarán el estado de retorno de todos modos si no hay comandos involucrados que puedan crear errores (x=${a!b}
casos mentales , pero irrelevantes aquí). - ¿Qué quieres decir con "comando sin nombre de comando" ?Puede definir (y usar) una función de shell:
Entonces
Podría decirse que esto es "hacer trampa", ya que hace una copia
$?
en lacheck_exit_status
lista de argumentos.Esto puede parecer un poco incómodo, y lo es. (Eso a veces sucede cuando impone restricciones arbitrarias a los problemas). Esto puede parecer inflexible, pero no lo es. Puede hacer
check_exit_status
más complejo, agregando argumentos que le digan qué pruebas hacer en el valor de estado de salida.fuente
Para responder a su pregunta directa, no, no es posible mantenerse
$?
inalterado. Y este es uno de esos casos en los que sospecho que te estás enfocando en el problema equivocado. Una variable temporal es la forma estándar y preferida para obtener el efecto que está buscando. Es tan estándar que sugeriría abandonar (o repensar) cualquier razón que piense que tiene para no querer usar una; Dudo mucho que valga la complejidad adicional agregada por cualquier otro método.Si solo pregunta por simple curiosidad, entonces la respuesta es no.
fuente
$?
o algo así?Aquí está mi fragmento de código para retener un estado de salida anterior sin salir del script / shell actual
fuente