输出文件描述符重定向

output file descriptor redirection

我需要能够将输出重定向到文件并检查 KSH 中脚本的 return 代码(不能使用 pipestatus 或 pipefail),我找到了解决方案,但我不确定文件描述符 4 的意义是什么,有人可以解释一下吗?

{
rc=$(
{
  {
    . somescript.sh 2>&1
    echo "$?" >&3
  } | tee -a somefile.txt
} 3>&1 >&4 4>&-
)
} 4>&1

echo "${rc}"

rc=$(...) 表示 return 代码将是 (...) 中的代码打印在文件描述符 (fd) 1 上的任何内容。因此,不知何故,somescript.sh 输出必须从 fd 1 中移出,然后再带回来。 echo 行将 somescript.sh 的 return 代码输出到 fd 3。然后,3>&1 将保存的 return 代码发送到 $(...) 期望的 fd 1。但是,这意味着旧的 fd 1(来自 {somescript 2>&1 } | tee)无处可去。所以旧的 fd 1 被重定向到 fd 4>&4 (并且输入端被 4>&- 关闭,因为它不会被使用)。然后,一旦 $(...) 结束,末尾的 4>&1 会将 somescript|tee 的输出放回 fd 1 其他程序期望的位置。

哇!

如果没有 >&4,由于 3>&1somescript.sh 的输出和 echo "$?" 的输出将在 fd 1 上混合。所以fd4是在fd1携带return代码的时候somescript.sh的实际输出的握笔

如果您愿意使用命名管道,则可以免除所有文件描述符争论:

mkfifo p
tee -a somefile.txt < p &
. somescript.sh > p
rc=$?

在这里,我们 运行 tee 在后台,让它从命名管道 p 读取输入。该作业启动后,我们获取脚本并将其输出重定向到命名管道。脚本完成后,您可以使用普通赋值语句将其退出状态保存到 rc。这也将关闭管道的外壳端,这将导致另一端也关闭并允许 tee 退出。