(16 réponses)
Fermé il y a 7 ans.
Considérez le code source :
#!/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;
Sortie :
Exit status: 1
Exit status: 0
- Variable
$exit_status
capture le statut de sortie de Child.sh et est donc1
. - Dans le 2ème cas,
$exit_status
capture le statut de sortie de tee, qui est.
Alors, comment puis-je capturer le statut de sortie et également utiliser tee ?
Réponse acceptée :
Reproduit (et amélioré) à partir de la FAQ comp.unix.shell (puisque j'ai écrit cette section de la FAQ) :
Comment puis-je obtenir le code de sortie de cmd1 dans cmd1|cmd2
Tout d'abord, notez que le code de sortie cmd1 peut être différent de zéro et ne signifie toujours pas
une erreur. Cela se produit par exemple dans
cmd | head -n 1
vous pouvez observer un état de sortie 141 (ou 269 avec ksh93, ou 397 avec yash) de cmd
,
mais c'est parce que cmd
a été interrompu par un signal SIGPIPE lorsque head -n 1
terminé après avoir lu une ligne.
Connaître l'état de sortie des éléments d'un pipeline
cmd1 | cmd2 | cmd3
avec zsh (et fish 3.1+) :
Les codes de sortie sont fournis dans le pipestatus
tableau spécial. cmd1
le code de sortie est dans $pipestatus[1]
, cmd3
code de sortie dans $pipestatus[3]
, de sorte que $status
/$?
est toujours le même que $pipestatus[-1]
.
avec bash :
Les codes de sortie sont fournis dans le PIPESTATUS
tableau spécial. cmd1
le code de sortie est dans ${PIPESTATUS[0]}
, cmd3
code de sortie dans ${PIPESTATUS[2]}
, de sorte que $?
est toujours identique à ${PIPESTATUS[-1]}
(ou ${PIPESTATUS[@]: -1}
pour les versions antérieures à 4.2).
avec n'importe quel autre obus de type Bourne
Vous devez utiliser une astuce pour transmettre les codes de sortie au shell principal. Vous pouvez le faire
en utilisant un pipe(2). Au lieu d'exécuter cmd1
, vous exécutez cmd1; echo "$?"
et assurez-vous que $ ? fait son chemin vers le shell.
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"
Codes de sortie dans $ec1
, $ec2
, $ec3
.
avec un shell POSIX
Vous pouvez utiliser cette fonction pour vous faciliter la tâche :
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"
}
Utilisez-le comme :
run cmd1 | cmd2 | cmd3
les codes de sortie sont dans $pipestatus_1
, $pipestatus_2
, $pipestatus_3
et $?
est le statut de sortie non nul le plus à droite (comme avec le pipefail
option de certains obus).