web-dev-qa-db-fra.com

Obtenir le code de sortie pour la commande dans bash / ksh

Je veux écrire du 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 souhaite. Où j'ai fait une erreur?

52
Kolesar

Ci-dessous 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 examinez ce code, voici quelques modifications que j'ai apportées:

  • l'utilisation de typeset n'est pas nécessaire, mais constitue une bonne pratique. Cela fait cmnd et ret_code local à safeRunCommand
  • utilisation de ret_code n'est pas nécessaire, mais c'est une bonne pratique de stocker le code de retour dans une variable (et de 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
  • transmettez la commande avec des guillemets entourant la commande comme safeRunCommand "$command". Si vous ne le faites pas, cmnd obtiendra uniquement la valeur ls et non ls -l. Et c'est encore plus important si votre commande contient des pipes.
  • vous pouvez utiliser typeset cmnd="$*" au lieu de typeset cmnd="$1" _ si vous voulez conserver les espaces. Vous pouvez essayer les deux en fonction de la complexité de votre argument de commande.
  • eval est utilisé pour évaluer si une commande contenant des tuyaux peut fonctionner correctement

NOTE: N'oubliez pas 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 retournera 0 sinon 1.

J'avais testé avec KSH/BASH. Et ça a bien fonctionné. Faites-moi savoir si vous rencontrez des problèmes en cours d'exécution.

66
havexz

Essayer

safeRunCommand() {
   "$@"

   if [ $? != 0 ]; then
      printf "Error when executing command: '$1'"
      exit $ERROR_CODE
   fi
}
5
sehe

Ce devrait être $cmd Au lieu de $($cmd). Fonctionne bien avec ça sur ma boîte.

Edit: Votre script ne fonctionne que pour les commandes one-Word, comme ls. Cela ne fonctionnera pas pour "ls cpp". Pour que cela fonctionne, remplacez cmd="$1"; $cmd Par "$@". Et, n'exécutez pas votre script en tant que command="some cmd"; safeRun command, Exécutez-le en tant que safeRun some cmd.

De plus, lorsque vous devez déboguer vos scripts bash, exécutez-le avec l'indicateur '-x'. [bash -x s.sh].

2
Priyank Bhatnagar

Il y a plusieurs problèmes avec votre script.

Les fonctions (sous-routines) doivent être déclarées avant de tenter de les appeler. Vous voulez probablement retourner () mais pas exit () de votre sous-routine pour permettre au bloc appelant de tester le succès ou l'échec d'une commande particulière. Cela dit, vous ne capturez pas 'ERROR_CODE', donc il s'agit toujours de zéro (non défini).

Il est également judicieux d'entourer vos références variables d'accolades. Votre code pourrait ressembler à:

#!/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
JRFerguson

L'idée normale serait d'exécuter la commande puis d'utiliser $? pour obtenir le code de sortie. Cependant, il arrive parfois que vous ayez plusieurs cas dans lesquels vous devez obtenir le code de sortie. Par exemple, vous devrez peut-être masquer la sortie tout en renvoyant le code de sortie ou imprimer 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é de supprimer la sortie de la commande pour laquelle vous voulez le code de sortie. Lorsque la sortie est supprimée pour la commande, le code de sortie sera directement renvoyé par la fonction.

Personnellement, j'aime bien mettre cette fonction dans mon .bashrc fichier

Ci-dessous, je vous présente quelques façons d'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 que vous verrez s'affichera pour la commande grep en cours d'exécution, car il s'agit de la dernière commande en cours d'exécution. Pas le ls.

0
Nathan F.