【问题标题】:Get the exit code for a command in Bash and KornShell (ksh)在 Bash 和 KornShell (ksh) 中获取命令的退出代码
【发布时间】:2012-01-02 22:53:32
【问题描述】:

我想写这样的代码:

command="some command"

safeRunCommand $command

safeRunCommand() {
   cmnd=$1

   $($cmnd)

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

但是这段代码不能按我想要的方式工作。我在哪里做错了?

【问题讨论】:

    标签: bash unix ksh exit


    【解决方案1】:

    下面是固定代码:

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

    我用KornShellBash 进行了测试。它工作得很好。如果您在运行此程序时遇到问题,请告诉我。

    【讨论】:

    • 您可以看到$command 正在safeRunCommandprintf 语句中使用。您可以使用它,因为它是全球性的。所以我要把$command改成$cmnd(局部变量..
    • 谢谢@havexz。我怎样才能像这样运行命令:command="ls -l | grep *.log" 不幸的是,这个命令不起作用,而且我的所有命令都非常复杂,有许多管道 |、grep、awk、sed、...
    • 更新了代码,只保留了更健壮的一个soln。
    • 还有一个问题 :) 如何将函数 safeRunCommand 的输出添加到变量中,以防处理中断失败功能。
    • 也许我找到了答案。我可以写out=$(eval $cmnd),并在调用safeRunCommand函数后使用out变量吗?
    【解决方案2】:

    试试

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

    【讨论】:

      【解决方案3】:

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

      您的脚本仅适用于单字命令,例如 ls。它不适用于“ls cpp”。为此,请将cmd="$1"; $cmd 替换为"$@"。并且,不要以command="some cmd"; safeRun command 运行您的脚本。以safeRun some cmd 运行它。

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

      【讨论】:

      • 快速详细说明为什么这是正确的:$($cmd) 将在 new shell 中执行 $cmd,而 $cmd 不会。
      • cmd="$@" 不起作用;相反,要么直接运行"$@"(如@sehe's answer),要么使用数组:cmd=("$@"); "${cmd[@]}"
      • @GordonDavisson:我先在我的系统上试一下,然后再在这里发布任何内容。它工作正常。这是 bash -x try.sh 上的输出。 + command='ls java' + safeRunCommand ls java + cmnd='ls java' + ls java 。和 cmd="hello world" 一样,不是吗?
      • @logic_max:在参数中有空格的命令上试试,比如safeRunCommand grep "this that" file.txt+ cmd='grep this that file.txt'+ grep this that file.txtgrep: that: No such file or directory
      • @logic_max:是的。我不确定为什么人们坚持在执行命令之前将命令存储在变量中;它只是创造了这样的限制。
      【解决方案4】:

      您的脚本有几处问题。

      函数(子例程)应在尝试调用它们之前声明。您可能希望从子例程中返回()而不是退出(),以允许调用块测试特定命令的成功或失败。除此之外,您不会捕获“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
      

      【讨论】:

      • cmnd="$@" 不起作用;相反,要么直接运行"$@"(如@sehe's answer),要么使用数组:cmnd=("$@"); "${cmnd[@]}"
      【解决方案5】:

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

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

      这将使您可以选择禁止输出您想要退出代码的命令。当命令的输出被抑制时,退出代码将直接由函数返回。

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

      下面我将展示一些你可以使用它的方法:


      # 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

      【讨论】:

        猜你喜欢
        • 2016-10-10
        • 2018-11-04
        • 2014-01-25
        • 1970-01-01
        • 2013-01-01
        • 2016-12-12
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        相关资源
        最近更新 更多