Obtenir le code de sortie de la commande dans bash / ksh
Je veux écrire un code comme ceci:
command="some command"
safeRunCommand $command
safeRunCommand() {
cmnd=$1
$($cmnd)
if [ $? != 0 ]; then
printf "Error when executing command: '$command'"
exit $ERROR_CODE
fi
}
Mais ce code ne fonctionne pas comme je le veux. Où j'ai fait une erreur?
5 réponses
Voici le code fixe:
#!/bin/ksh
safeRunCommand() {
typeset cmnd="$*"
typeset ret_code
echo cmnd=$cmnd
eval $cmnd
ret_code=$?
if [ $ret_code != 0 ]; then
printf "Error : [%d] when executing command: '$cmnd'" $ret_code
exit $ret_code
fi
}
command="ls -l | grep p"
safeRunCommand "$command"
Maintenant, si vous regardez dans ce code, peu de choses que j'ai changées sont:
- utiliser
typeset
n'est pas nécessaire, mais une bonne pratique. Ilcmnd
etret_code
local àsafeRunCommand
- l'utilisation de
ret_code
n'est pas nécessaire mais une bonne pratique pour stocker le code de retour dans une variable (et le stocker dès que possible) afin que vous puissiez l'utiliser plus tard comme je l'ai fait dansprintf "Error : [%d] when executing command: '$command'" $ret_code
- passez la commande avec des guillemets entourant la commande comme
safeRunCommand "$command"
. Si vous n'avez pas alorscmnd
n'obtiendra que la valeurls
et nonls -l
. Et c'est encore plus important si votre commande contient des tuyaux. - , vous pouvez utiliser
typeset cmnd="$*"
au lieu detypeset cmnd="$1"
si vous souhaitez conserver les espaces. Vous pouvez essayer avec les deux en fonction de la complexité de votre argument de commande. - eval est utilisé pour évaluer afin que la commande contenant des tuyaux puisse fonctionner correctement
NOTE: souvenez-vous que certaines commandes donnent 1 comme code de retour même s'il n'y a pas d'erreur comme grep
. Si grep
a trouvé quelque chose, il le fera retour 0 sinon 1.
J'avais testé avec KSH / BASH. Et il a bien fonctionné. Faites-moi savoir si vous rencontrez des problèmes en cours d'exécution.
Essayez
safeRunCommand() {
"$@"
if [ $? != 0 ]; then
printf "Error when executing command: '$1'"
exit $ERROR_CODE
fi
}
, Il devrait être $cmd
au lieu de $($cmd)
. Fonctionne très bien avec ça sur ma boîte.
Edit: votre script ne fonctionne que pour les commandes à un mot, comme ls. Cela ne fonctionnera pas pour "ls cpp". Pour que cela fonctionne, remplacez cmd="$1"; $cmd
avec "$@"
. Et, n'exécutez pas votre script comme command="some cmd"; safeRun command
, exécutez-le comme safeRun some cmd
.
Aussi, lorsque vous devez déboguer vos scripts bash, exécutez avec l'indicateur '- x'. [bash-x s.sh].
Il y a plusieurs choses qui ne vont pas avec votre script.
Les fonctions (sous-routines) doivent être déclarées avant de tenter de les appeler. Vous voulez probablement return () mais pas exit () de votre sous-programme pour permettre au bloc appelant de tester le succès ou l'échec d'une commande particulière. Cela mis à part, vous ne capturez pas 'ERROR_CODE' donc c'est toujours zéro (indéfini).
Il est également recommandé d'entourer vos références de variables d'accolades. Votre code pourrait ressembler comme:
#!/bin/sh
command="/bin/date -u" #...Example Only
safeRunCommand() {
cmnd="$@" #...insure whitespace passed and preserved
$cmnd
ERROR_CODE=$? #...so we have it for the command we want
if [ ${ERROR_CODE} != 0 ]; then
printf "Error when executing command: '${command}'\n"
exit ${ERROR_CODE} #...consider 'return()' here
fi
}
safeRunCommand $command
command="cp"
safeRunCommand $command
L'idée normale serait d'exécuter la commande, puis d'utiliser $?
pour obtenir le code de sortie. Cependant, certaines fois, vous avez plusieurs cas dans lesquels vous devez obtenir le code de sortie. Par exemple, vous devrez peut-être masquer sa sortie, mais toujours renvoyer le code de sortie, ou imprimer à la fois le code de sortie et la sortie.
ec() { [[ "$1" == "-h" ]] && { shift && eval $* > /dev/null 2>&1; ec=$?; echo $ec; } || eval $*; ec=$?; }
Cela vous donnera la possibilité d'éviter la sortie de la commande que vous voulez le code de sortie pour. Lorsque la sortie est supprimée pour la commande, le code de sortie sera directement de retour de la fonction.
Personnellement, j'aime mettre cette fonction dans mon fichier .bashrc
Ci-dessous, je démontre quelques façons dont vous pouvez utiliser ceci:
# In this example, the output for the command will be
# normally displayed, and the exit code will be stored
# in the variable $ec.
$ ec echo test
test
$ echo $ec
0
# In this example, the exit code is output
# and the output of the command passed
# to the `ec` function is suppressed.
$ echo "Exit Code: $(ec -h echo test)"
Exit Code: 0
# In this example, the output of the command
# passed to the `ec` function is suppressed
# and the exit code is stored in `$ec`
$ ec -h echo test
$ echo $ec
0
Solution à votre code en utilisant cette fonction
#!/bin/bash
if [[ "$(ec -h 'ls -l | grep p')" != "0" ]]; then
echo "Error when executing command: 'grep p' [$ec]"
exit $ec;
fi
, Vous devez également noter que le code de sortie vous allez voir sera pour la
grep
commande est en cours d'exécution, comme c'est la dernière commande exécutée. Pas lels
.