在Bash和KornShell (ksh)中获取命令的退出代码



我想写这样的代码:

command="some command"
safeRunCommand $command
safeRunCommand() {
   cmnd=$1
   $($cmnd)
   if [ $? != 0 ]; then
      printf "Error when executing command: '$command'"
      exit $ERROR_CODE
   fi
}

但是这段代码没有按我想要的方式工作。我哪里出错了?

下面是固定代码:

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

现在,如果你看一下这段代码,我改变的几件事是:

  • 使用typeset是不必要的,但这是一个很好的做法。它使cmndret_code局部于safeRunCommand
  • 使用ret_code是不必要的,但是将返回代码存储在一些变量中(并尽快存储它)是一个很好的做法,这样您就可以像我在printf "Error: [%d] when executing command: '$command'" $ret_code
  • 中那样稍后使用它。
  • 传递带有引号的命令,如safeRunCommand "$command"。如果不这样做,那么cmnd将只获得ls而不是ls -l的值。如果您的命令包含管道,则更重要。
  • 如果你想保留空格,你可以使用typeset cmnd="$*"而不是typeset cmnd="$1"。您可以根据命令参数的复杂程度来尝试两者。
  • 'eval'用于求值,以便包含管道的命令可以正常工作

注意:请记住一些命令给出1作为返回码,即使没有任何错误,如grep。如果grep发现了什么,它将返回0,否则返回1。

我用KornShell和Bash测试过。它运行得很好。

Try

safeRunCommand() {
   "$@"
   if [ $? != 0 ]; then
      printf "Error when executing command: '$1'"
      exit $ERROR_CODE
   fi
}

应该是$cmd而不是$($cmd)。它在我的盒子上工作得很好。

您的脚本只适用于一个单词的命令,如ls。它将不工作的"ls "为此,将cmd="$1"; $cmd替换为"$@"。并且,不要以command="some cmd"; safeRun command的身份运行脚本。作为safeRun some cmd运行

另外,当您必须调试Bash脚本时,请使用'-x'标志执行。[bash -x .sh].

你的脚本有几个问题。

函数(子程序)应该在尝试调用它们之前声明。您可能希望从子例程返回()而不是退出(),以允许调用块测试特定命令的成功或失败。除此之外,您没有捕获'ERROR_CODE',因此它始终为零(未定义)。

用花括号括住变量引用也是个好习惯。您的代码可能看起来像:

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

通常的想法是运行命令,然后使用$?获取退出代码。但是,有时在多种情况下需要获得退出代码。例如,您可能需要隐藏它的输出,但仍然返回退出代码,或者打印退出代码和输出。

ec() { [[ "$1" == "-h" ]] && { shift && eval $* > /dev/null 2>&1; ec=$?; echo $ec; } || eval $*; ec=$?; }

这将为您提供选项,以抑制您想要退出代码的命令的输出。当命令的输出被抑制时,退出代码将直接由函数返回。

我个人喜欢把这个函数放在我的中。bashrc 文件(.


# 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

使用这个函数 解决你的代码
#!/bin/bash
if [[ "$(ec -h 'ls -l | grep p')" != "0" ]]; then
    echo "Error when executing command: 'grep p' [$ec]"
    exit $ec;
fi

您还应该注意,您将看到的退出代码将用于正在运行的grep命令,因为它是正在执行的最后一个命令。不是ls

最新更新