我看到在 SE 上有很多关于使用exec在 Bash 中重定向的问题,但似乎没有一个能回答我的问题。
我想要完成的是将脚本中所有输出重定向到stderr到临时 fd,并仅在脚本未成功终止的情况下将其恢复到stderr 。在非成功终止的情况下,需要恢复stderr内容的能力,以便向调用者返回有关错误的信息。将stderr重定向到/dev/nul
将丢弃不相关的噪音和有用的信息。应尽可能避免显式临时文件,因为它们会增加许多其他问题(请参阅https://dev.to/philgibbs/avoiding-temporary-files-in-shell-scripts)。标准输出的内容应该透明地返回给调用者。如果脚本未成功终止,它将被忽略,但脚本不需要关心这一点。
这样做的原因是脚本是从另一个程序调用的,该程序认为任何输出到stderr都是错误,而不是测试非零退出代码。在下面的示例中,openssl向stderr回显了一个进度指示器,成功完成后应该忽略它。
下面是我的脚本的简化版本(请注意,这里的openssl只是任意且可能更复杂的指令的占位符):
#!/bin/bash
set -euo pipefail
# Redirect stderr to temp fd 3
exec 3>&2
# In case of error, copy contents of fd 3 to stderr
trap 'cat <&3 >&2' ERR
# Upon exit, restore original stderr and close fd 3
trap 'exec 2>&3 3>&-' EXIT
# This nonetheless outputs the progress indicator to stderr
openssl genpkey -algorithm RSA
但是我显然遗漏了一些东西,因为脚本在成功终止时不断打印出stderr的内容,但现在在失败时会阻塞。我想我对exec的重定向如何工作感到困惑。我错了什么?
感谢上面评论中的所有人,他们帮助我指明了正确的方向。这似乎是我一直在寻找的答案,深受其他 SE 答案的启发:
欢迎提出进一步改进的想法。