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

发布于 2024-12-17 14:18:05 字数 280 浏览 0 评论 0原文

我想编写这样的代码:

command="some command"

safeRunCommand $command

safeRunCommand() {
   cmnd=$1

   $($cmnd)

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

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

I want to write code like this:

command="some command"

safeRunCommand $command

safeRunCommand() {
   cmnd=$1

   $($cmnd)

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

But this code does not work the way I want. Where did I make the mistake?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

烦人精 2024-12-24 14:18:05

下面是固定的代码:

#!/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“执行命令时的错误:[%d]:'$command'”$ret_code
  • 传递带有引号的命令命令如 safeRunCommand "$command"。如果不这样做,cmnd 将仅获得值 ls 而不是 ls -l。如果您的命令包含管道,则更为重要。
  • 如果您想保留空格,可以使用 typeset cmnd="$*" 而不是 typeset cmnd="$1" 。您可以尝试两者,具体取决于命令参数的复杂程度。
  • 'eval' 用于评估,以便包含管道的命令可以正常工作

注意:请记住一些命令给出 1 作为返回码,即使没有任何像 grep.如果 grep 发现某些内容,它将返回 0,否则返回 1。

我已经使用 KornShell 进行了测试Bash。而且效果很好。如果您在运行此程序时遇到问题,请告诉我。

Below is the fixed code:

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

Now if you look into this code, the few things that I changed are:

  • use of typeset is not necessary, but it is a good practice. It makes cmnd and ret_code local to safeRunCommand
  • use of ret_code is not necessary, but it is a good practice to store the return code in some variable (and store it ASAP), so that you can use it later like I did in printf "Error: [%d] when executing command: '$command'" $ret_code
  • pass the command with quotes surrounding the command like safeRunCommand "$command". If you don’t then cmnd will get only the value ls and not ls -l. And it is even more important if your command contains pipes.
  • you can use typeset cmnd="$*" instead of typeset cmnd="$1" if you want to keep the spaces. You can try with both depending upon how complex is your command argument.
  • 'eval' is used to evaluate so that a command containing pipes can work fine

Note: Do remember some commands give 1 as the return code even though there isn't any error like grep. If grep found something it will return 0, else 1.

I had tested with KornShell and Bash. And it worked fine. Let me know if you face issues running this.

ま昔日黯然 2024-12-24 14:18:05

尝试

safeRunCommand() {
   "$@"

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

Try

safeRunCommand() {
   "$@"

   if [ $? != 0 ]; then
      printf "Error when executing command: '$1'"
      exit $ERROR_CODE
   fi
}
场罚期间 2024-12-24 14:18:05

它应该是 $cmd 而不是 $($cmd)。和我的盒子上的效果很好。

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

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

It should be $cmd instead of $($cmd). It works fine with that on my box.

Your script works only for one-word commands, like ls. It will not work for "ls cpp". For this to work, replace cmd="$1"; $cmd with "$@". And, do not run your script as command="some cmd"; safeRun command. Run it as safeRun some cmd.

Also, when you have to debug your Bash scripts, execute with '-x' flag. [bash -x s.sh].

深海蓝天 2024-12-24 14:18:05

您的脚本有几个问题。

函数(子例程)应在尝试调用之前进行声明。您可能希望在子例程中使用 return() 但不使用 exit(),以允许调用块测试特定命令的成功或失败。除此之外,您不会捕获“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

There are several things wrong with your script.

Functions (subroutines) should be declared before attempting to call them. You probably want to return() but not exit() from your subroutine to allow the calling block to test the success or failure of a particular command. That aside, you don't capture 'ERROR_CODE' so that is always zero (undefined).

It's good practice to surround your variable references with curly braces, too. Your code might look like:

#!/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
挽袖吟 2024-12-24 14:18:05

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

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

The normal idea would be to run the command and then use $? to get the exit code. However, sometimes you have multiple cases in which you need to get the exit code. For example, you might need to hide its output, but still return the exit code, or print both the exit code and the output.

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

This will give you the option to suppress the output of the command you want the exit code for. When the output is suppressed for the command, the exit code will directly be returned by the function.

I personally like to put this function in my .bashrc file.

Below I demonstrate a few ways in which you can use this:


# 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 to your code using this function

#!/bin/bash
if [[ "$(ec -h 'ls -l | grep p')" != "0" ]]; then
    echo "Error when executing command: 'grep p' [$ec]"
    exit $ec;
fi

You should also note that the exit code you will be seeing will be for the grep command that's being run, as it is the last command being executed. Not the ls.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文