(16 respuestas)
Cerrado hace 7 años.
Considere el código fuente:
#!/usr/bin/ksh
# No tee
ksh Child.sh;
exit_status=$?;
echo "Exit status: ${exit_status}"
# Using tee
ksh Child.sh | tee -a log.txt;
exit_status=$?;
echo "Exit status: ${exit_status}"
#!/usr/bin/ksh
...
exit 1;
Salida:
Exit status: 1
Exit status: 0
- Variable
$exit_status
está capturando el estado de salida de Child.sh y también1
. - En el segundo caso,
$exit_status
está capturando el estado de salida de tee, que es.
Entonces, ¿cómo capturo el estado de salida y también uso tee?
Respuesta aceptada:
Reproducido (y mejorado) de las preguntas frecuentes de comp.unix.shell (ya que yo escribí esa sección de las preguntas frecuentes):
¿Cómo obtengo el código de salida de cmd1 en cmd1|cmd2
?
Primero, tenga en cuenta que el código de salida de cmd1 podría ser distinto de cero y aun así no
significar un error. Esto sucede, por ejemplo, en
cmd | head -n 1
puede observar un estado de salida 141 (o 269 con ksh93, o 397 con yash) de cmd
,
pero es porque cmd
fue interrumpido por una señal SIGPIPE cuando head -n 1
terminado después de haber leído una línea.
Para conocer el estado de salida de los elementos de un pipeline
cmd1 | cmd2 | cmd3
con zsh (y fish 3.1+):
Los códigos de salida se proporcionan en el pipestatus
matriz especial. cmd1
el código de salida está en $pipestatus[1]
, cmd3
código de salida en $pipestatus[3]
, de modo que $status
/$?
siempre es igual a $pipestatus[-1]
.
con bash:
Los códigos de salida se proporcionan en el PIPESTATUS
matriz especial. cmd1
el código de salida está en ${PIPESTATUS[0]}
, cmd3
código de salida en ${PIPESTATUS[2]}
, por lo que $?
siempre es igual a ${PIPESTATUS[-1]}
(o ${PIPESTATUS[@]: -1}
para versiones anteriores a la 4.2).
con cualquier otro proyectil tipo Bourne
Necesita usar un truco para pasar los códigos de salida al shell principal. Puedes hacerlo
usando una tubería(2). En lugar de ejecutar cmd1
, ejecuta cmd1; echo "$?"
y asegúrese de
$? se dirige al caparazón.
exec 3>&1
code=`
# now, inside the backticks, fd4 goes to the pipe
# whose other end is read and stored in $code for
# later evaluation; fd1 is the normal standard output
# preserved the line before with exec 3>&1
exec 4>&1 >&3 3>&-
{
cmd1 4>&-; echo "ec1=$?;" >&4
} | {
cmd2 4>&-; echo "ec2=$?;" >&4
} | cmd3 4>&-
echo "ec3=$?;" >&4
`
exec 3>&-
eval "$code"
Códigos de salida en $ec1
, $ec2
, $ec3
.
con un shell POSIX
Puedes usar esta función para hacerlo más fácil:
run() {
j=1
while eval "${pipestatus_$j+:} false"; do
unset "pipestatus_$j"
j=$(($j+1))
done
j=1 com= k=1 l=
for arg do
case $arg in
('|')
com="$com {
$l "'3>&-
echo "pipestatus_'$j'=$?" >&3
} 4>&- |'
j=$(($j+1)) l=;;
(*)
l="$l "${$k}""
esac
k=$(($k+1))
done
com="$com $l"' 3>&- >&4 4>&-
echo "pipestatus_'$j'=$?"'
{ eval "$(exec 3>&1; eval "$com")"; } 4>&1
j=1
ret=0
while eval "${pipestatus_$j+:} false"; do
eval '[ "$pipestatus_'"$j"'" -eq 0 ] || ret=$pipestatus_'"$j"
j=$(($j+1))
done
return "$ret"
}
Úselo como:
run cmd1 | cmd2 | cmd3
los códigos de salida están en $pipestatus_1
, $pipestatus_2
, $pipestatus_3
y $?
es el estado de salida distinto de cero más a la derecha (como con el pipefail
opción de algunas conchas).