关闭 stdout fd 会给出错误,而关闭 stderr fd 则不会

关闭 stdout fd 会给出错误,而关闭 stderr fd 则不会

以下测试代码给出错误“错误的文件描述符”。为什么会这样?这只是一个测试代码,用于理解文件描述符及其与管道的交互。

示例1)

❯ echo "hello" 1>&2 1>&- |& echo "world"
world
zsh: 1: bad file descriptor

示例2)

echo "hello" 1>&2 1>&- | cat <<< "world"
zsh: write error: bad file descriptor
world

例3)

# Does not give error
❯ echo "helloworld" >&-
# Gives stdin? error
❯ cat <<< "helloworld" >&-
cat: stdin: Bad file descriptor

如果我只关闭 stderr,或同时关闭 stdout 和 stderr,那么我不会收到“错误文件描述符”错误。例如,以下两个都不会给出该错误:

❯ echo "hello" 1>&2 2>&- |& echo "world"
❯ echo "hello" 2>&1 2>&- |& echo "world"
❯ echo "hello" 1>&2 1>&- 2>&- |& echo "world"

答案1

|&2>&1 |(如有记录的)。在执行其他重定向之前,左侧的标准输出连接到管道的写入侧,但标准错误在最后连接到当时的标准输出。如果标准输出被重定向,或者如您的示例所示,被关闭,这会产生影响。使用foo 1>&- |& bar、 或等效的foo 1>&- 2>&1 | bar、或者仅使用foo 1>&- 2>&1,在应用 fd 2 到 fd 1 的重定向时,文件描述符 1 上没有任何内容。

使用 时foo 1>&2 1>&- | bar,首先将 的标准输出foo连接到管道的写入端,然后(假设multios已打开)1>&2创建一个到内置 T 型进程的管道,该进程将写入|操作员创建的管道以及当时在文件描述符 2 上(即终端)。然后1>&-关闭标准输出,因此如果foo尝试写入标准输出,则此写入将失败。不管类似 tee 的进程写入多少个地方:在1>&-它无法接收任何输入之后。

^我在文档中找不到指定的内容,但这就是 shell 传统上所做的事情,它是由 POSIX 指定。如果您不确定,您可以检查源代码、系统调用跟踪,或者您可以从各种重定向实验的结果(例如您一直在进行的实验)中推断出它。

相关内容