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?

45
demandé sur javaPlease42 2011-11-21 16:32:18

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. Il cmnd et ret_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 dans printf "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 alors cmnd n'obtiendra que la valeur ls et non ls -l. Et c'est encore plus important si votre commande contient des tuyaux.
  • , vous pouvez utiliser typeset cmnd="$*" au lieu de typeset 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.

59
répondu havexz 2016-03-24 03:08:46

Essayez

safeRunCommand() {
   "$@"

   if [ $? != 0 ]; then
      printf "Error when executing command: '$1'"
      exit $ERROR_CODE
   fi
}
5
répondu sehe 2011-11-21 12:53:07

, 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].

2
répondu Priyank Bhatnagar 2011-11-22 05:26:50

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
1
répondu JRFerguson 2011-11-21 14:31:14

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 le ls.

0
répondu Nathan Fiscaletti 2017-09-11 18:55:01