【问题标题】:How to get exit codes for different sections of a command in bash如何在bash中获取命令不同部分的退出代码
【发布时间】:2019-07-19 20:59:45
【问题描述】:

假设我的 bash 脚本中有一行 ssh bad@location "find -name 'fruit.txt' | grep "Apple",我正在尝试检索 sshfind . -name 'fruit.txt' 和 "grep "Apple` 的退出代码,以查看哪个命令出错。

到目前为止,我已经尝试过类似echo $? ${PIPESTATUS[0]} ${PIPESTATUS[1]} 的方法,但在这种情况下,$? 的返回值与${PIPESTATUS[0]} 相同。我只需要返回第一个非零退出代码以及 dmesg 以进行调试。

我也考虑过使用set -o pipefail,如果有任何命令错误,它将返回失败退出代码,但我想知道哪个命令调试失败。

我想获得 255 的退出代码(来自 ssh)及其对应的 dmesg,或者以某种方式获得所有退出代码。

【问题讨论】:

  • 运行ssh bad@location "find -name 'fruit'"时,从调用ssh的进程来看,只有一个退出状态——find返回给ssh,然后ssh返回给调用者.
  • @CharlesDuffy,感谢您的提示!我不知道。
  • @AmandaNguyen :您在帖子中声明的管道有两个进程,sshgrep。 PIPESTATUS[0] 与ssh 的退出代码相关,PIPESTATUS[1] 与grep 的退出代码相关。

标签: bash


【解决方案1】:

ssh 只返回 一个 退出状态(每个 channel)给调用 shell;如果您想获取远程运行的各个管道组件的退出状态,您需要远程收集它们,将它们与数据一起放入,然后将它们解析出来。如果你有一个非常新版本的 bash,一种方法是这样的:

#!/usr/bin/env bash

# note <<'EOF' not just <<EOF; with the former, the local shell does not munge
# heredoc contents.
remote_script=$(cat <<'EOF'
  tempfile=$(mktemp "${TMPDIR:-/tmp}/output.XXXXXX"); mktemp_rc=$?
  find -name 'fruit.txt' | grep Apple >"$tempfile"
  printf '%s\0' "$mktemp_rc" "${PIPESTATUS[@]}"
  cat "$tempfile"
  rm -f -- "$tempfile"
  exit 0  # so a bad exit status will be from ssh itself
EOF
)

# note that collecting a process substitution PID needs bash 4.4!
exec {ssh_fd}< <(ssh bad@location "$remote_script" </dev/null); ssh_pid=$!
IFS= read -r -d '' mktemp_rc <&$ssh_fd   # read $? of mktemp
IFS= read -r -d '' find_rc <&$ssh_fd     # read $? of find
IFS= read -r -d '' grep_rc <&$ssh_fd     # read $? of grep
cat <&$ssh_fd                            # spool output of grep to our own output
wait "$ssh_pid"; ssh_rc=$?               # let ssh finish and read its $?

echo "mktemp exited with status $mktemp_rc" >&2
echo "find exited with status $find_rc" >&2
echo "grep exited with status $grep_rc" >&2
echo "ssh exited with status $ssh_rc" >&2

这是如何工作的?

  • exec {fd_var_name}&lt; &lt;(...) 使用 bash 4.1 自动文件描述符分配 功能生成文件描述符编号,并将其与从运行 ... 的进程替换中读取的内容相关联。
  • 在 bash 4.4 或更高版本中,进程替换还设置了$!,因此可以捕获它们的 PID,稍后为它们提供wait 并收集它们的退出状态;这是我们存储在ssh_pid 中的内容。
  • IFS= read -r -d '' varname 从标准输入读取到下一个 NUL(在 read -d '' 中,'' 的第一个字符被视为输入的结尾;作为 C 派生语言中的空字符串,字符串的第一个字节是它的 NUL 终止符)。

理论上这可以通过在退出状态值之前写入输出之前来变得更容易——这样你就不需要远程机器上的临时文件——但需要注意的是,如果find | grep 输出中的任何地方都有一个 NUL,然后 reads 可以获取其中的一些输出。 (同样,您可以将输出存储在变量中而不是临时文件中,但同样会破坏流输出中的任何 NUL)。

【讨论】:

    猜你喜欢
    • 2012-01-02
    • 2016-10-10
    • 2018-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-01
    • 2013-08-26
    • 1970-01-01
    相关资源
    最近更新 更多