由于我错误地在 SO 中使用 bash shell 标签询问并认为这是一个更合适的地方,因此我重新提出了我的问题。
我正在 AWS DataPipeline 中编写一个连接到关系数据库的 shell 脚本,即使对于 SQL 错误,退出代码也是 0,因此我需要捕获 + 重定向 stderr。
我将 stderr 重定向到另一个文件以检查其内容,但仍然希望填充 stderr。原因是 DataPipeline 捕获所有 stderr 和 stdout 并将它们全部放入 1 个日志中。由于重定向,它不会从失败的 sql 命令中捕获 stderr。有没有办法仍然填充 stderr?我目前拥有的是:
/bin/snowsql -f /home/scripts/dev/dev.sql 2> /home/scripts/dev/stderr.txt
以下内容适用于 Bash:
/bin/snowsql -f /home/scripts/dev/dev.sql 2> >(tee /home/scripts/dev/stderr.txt >&2)
我找不到 shell 进程替换的正确语法。在 shell 中执行上述操作相当于什么?
答案1
在 中sh
,您只能通过管道将 stdout 传递给另一个命令,因此您必须首先交换 stdout 和 stderr:
/bin/snowsql -f /home/scripts/dev/dev.sql 3>&2 2>&1 >&3 3>- | tee /home/scripts/dev/stderr.txt
重定向是从左到右执行的,除了管道,它是在一开始创建的,所以它的作用是:
- 打开管道并在其中重定向 stdout (
|
) - 复制 stderr 并将文件描述符 3(任意)重定向到它,以便稍后重用它 (
3>&2
) - 复制 stdout(当前重定向到管道)并将 stderr 重定向到它 (
2>&1
) - 重复文件描述符 3(当前在原始 stderr 中重定向)并将 stdout 重定向到它 (
>&3
) - 关闭文件描述符 3 (
3>-
)
在这种状态下,我们交换了 stdout 和 stderr,并且管道接收 stderr。然后我们让它tee
完成将 stderr 写入文件的工作,并在自己的 stdout 上再次输出它。
感谢这个 StackOverflow 答案的提示:https://stackoverflow.com/a/2381643