bash - 如何在bash中获取命令不同部分的退出代码
问题描述
假设我的 bash 脚本中有一行,ssh bad@location "find -name 'fruit.txt' | grep "Apple"
我正在尝试检索, 和 "grep "Apple`的退出代码ssh
,以查看哪个命令出错。find . -name 'fruit.txt'
到目前为止,我已经尝试过类似的东西echo $? ${PIPESTATUS[0]} ${PIPESTATUS[1]}
,但看起来$?
返回的结果与本例中的相同${PIPESTATUS[0]}
。我只需要返回第一个非零退出代码以及 dmesg 以进行调试。
我也考虑过使用set -o pipefail
,如果有任何命令错误,它将返回失败退出代码,但我想知道哪个命令调试失败。
我想获得 255 的退出代码(来自 ssh)及其相应的 dmesg,或者以某种方式获得所有退出代码。
解决方案
ssh
只向调用外壳返回一个退出状态(每个通道);如果要获取远程运行的各个管道组件的退出状态,则需要远程收集它们,将它们与数据一起放入,然后将它们解析出来。如果你有一个非常新版本的 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}< <(...)
使用 bash 4.1自动文件描述符分配功能生成文件描述符编号,并将其与从进程替换运行中读取的内容相关联...
。- 在 bash 4.4 或更高版本中,还设置了进程替换
$!
,因此可以捕获它们的 PID,以便稍后wait
为它们收集并收集它们的退出状态;这就是我们存储的内容ssh_pid
。 IFS= read -r -d '' varname
从标准输入读取到下一个 NUL(在 中read -d ''
,第一个字符''
被视为输入的结尾;作为 C 派生语言中的空字符串,字符串的第一个字节是它的 NUL 终止符)。
从理论上讲,这可以通过在退出状态值之前写入输出来变得更容易——这样你就不需要远程机器上的临时文件——但需要注意的是,如果find | grep
输出中的任何地方都有 NUL,那么其中一些输出可以被read
s 获取。(同样,您可以将输出存储在变量而不是临时文件中,但同样,这会破坏流输出中的任何 NUL)。
推荐阅读
- ruby-on-rails - ActiveRecord less_than_or_equal_to 等值验证错误
- mpi - 使用安装在计算节点上的 mpirun 和 PBS
- cakephp - CakePHP 3.7.5 将字段的数据检索到控制器中
- php - 如何在隐式模型绑定上添加 where 子句?
- javascript - 导航菜单“活动”状态不起作用
- python - 从字典中提取值列表
- javascript - 如何显示搜索结果
- c# - C#编译失败表达式太长或编译复杂
- html - 针对表单中的最后一个表单字段,然后是一些
- objective-c - 使用 AFHTTPSessionManager 发送 POST 请求时如何向参数发送空白数据