Algunos comandos escriben advertencias insignificantes en stderr
pero devuelven el estado de salida 0
.
¿Hay alguna manera de verificar que el estado de salida del comando es 0
y stderr
está vacío, sin crear archivos temporales y con una sola declaración?
4 respuestas
Gracias @Cyrus y @chepner para los comentarios:
if stderr=$(command 2>&1 >/dev/null) && test -z "$stderr"; then echo "ok"; fi
El stderr
del command 2>&1 >/dev/null
se redirige a donde estaba stdout
antes, y el propio stdout
se redirige a /dev/null
. Luego, stderr
se asigna a la variable stderr
en stderr=$(command 2>&1 >/dev/null)
, y el código de salida de esta asignación es el de solo command
, por lo que se utiliza en {{X9 }}. Luego, si el código de salida de command
es cero (y solo en este caso), se verifica la segunda condición (test -z "$stderr"
), que prueba si la variable $stderr
es de longitud cero cuerda.
Yo sugiero:
stderr=$(your_command 2>&1 >/dev/null)
[[ $? == 0 ]] && [[ ${#stderr} == 0 ]] && echo okay
La esperanza a continuación es útil.
res=$(./test.out 2 >&1)
if [ $? -eq 0 ];then
stdout=$res
echo $stdout
else
return_code=$?
std_err=$res
echo $stderr
fi
Archivo correspondiente test.c en C
#include <stdio.h>
int main ( ) {
printf( "hello " );
fprintf( stderr, "HELP!" );
printf( " world\n" );
return 1;
}
Debido a cómo funciona set -o pipefail
, puede tomar stderr en una tubería y salir con un estado de salida distinto de cero de la tubería si hay algo en stderr. Entonces, básicamente, pipefail
realiza el estado binario y de salida o salida: si el comando sale con un estado de salida distinto de cero, pipefail
falla la tubería con este estado, si el comando sale con un estado de salida cero, entonces el derecho el lado de la tubería fallará con un estado de salida distinto de cero, por lo que toda la tubería saldrá con un estado de salida distinto de cero.
# Usage: exit_if_nonzero_or_stderr command [args...]
# Executes the command [args...] and
# exits with nonzero exit status
# if the command exits with nonzero exit status
# __or__
# the command outputs anything on stderr.
exit_if_nonzero_or_stderr() {
(
set -o pipefail
{ "$@" 1>&3 ;} 2>&1 | {
if IFS= read -r line; then
printf "%s\n" "$line"
cat
exit 1
fi
} >&2
) 3>&1
}
Probada contra todas las combinaciones:
tester() {
for i in \
'echo 1; true;' \
'echo 1; false;' \
'echo 1; echo 2 >&2; true;' \
'echo 1; echo 2 >&2; false;'
do
eval "f() { $i }"
set -o pipefail
exit_if_nonzero_or_stderr f 2> >( \
sed 's/^/stderr: /' >&2) |
sed 's/^/stdout: /';
echo "f() { $i } -> exit status: $?";
done
}
tester
Las salidas tester
:
stdout: 1
f() { echo 1; true; } -> exit status: 0
stdout: 1
f() { echo 1; false; } -> exit status: 1
stderr: 2
stdout: 1
f() { echo 1; echo 2 >&2; true; } -> exit status: 1
stdout: 1
stderr: 2
f() { echo 1; echo 2 >&2; false; } -> exit status: 1
Implementación alternativa y un poco más detallado y más consumo de memoria, pero más posix-ish que podría tomar stderr
a una variable y verificar si no es cero:
exit_if_nonzero_or_stderr2() {
local stderr ret
# redirect stdout to output with temporary file descriptor
# and grab stderr
{ stderr=$({ "$@" 1>&3 ;} 2>&1 ) ;} 3>&1
# remember return value
ret=$?
# if theres anything on stderr, output it
if [[ -n "$stderr" ]]; then
cat <<<"$stderr" >&2
# if stderr, always nonzero
return 1
fi
# else we return with the exit status of the command
return "$ret"
}
Nuevas preguntas
bash
Para preguntas sobre scripts escritos para el shell de comandos Bash. Para los scripts de shell con errores / errores de sintaxis, verifíquelos con el programa shellcheck (o en el servidor web shellcheck en https://shellcheck.net) antes de publicar aquí. Es más probable que las preguntas sobre el uso interactivo de Bash sean sobre el tema en Superusuario que en Stack Overflow.