如何在不关闭标准输入/标准输出的情况下关闭命名文件描述符?

sma*_*c89 4 bash io-redirection file-descriptors

exec {ec}< <(echo "puts 'hello'") && sudo ruby /proc/$$/fd/${ec}
Run Code Online (Sandbox Code Playgroud)

一旦我关闭它

exec <&"${ec}"-
Run Code Online (Sandbox Code Playgroud)

外壳退出。

在另一种情况下,我创建了这个文件描述符:

exec {gr}> >(/usr/bin/grep 'hello')
Run Code Online (Sandbox Code Playgroud)

然后我关闭它exec >&${gr}-,现在当我运行一个简单的命令时ls,没有打印任何内容。

我可以做,ls >&2并且肯定它显示了一些东西,但显然标准输出现在是 MIA。


我仍在学习所有这些文件描述符业务的工作原理,并希望得到一些指导。谢谢。

ilk*_*chu 6

Bash 的手册说

如果>&-<&-前面是{varname},则varname的值定义要关闭的文件描述符。

所以,它是exec {fd}>&-(或{fd}<&-)关闭它。

$ exec {fd}>foo.out
$ echo "$fd"
10
$ echo hi >&"$fd"             # works
$ exec {fd}>&-                # close it
$ echo ho >&"$fd"             # doesn't work any more
bash: "$fd": Bad file descriptor
$ cat foo.out
hi     
Run Code Online (Sandbox Code Playgroud)

exec <&"${ec}"-将命名为 in 的 fd 移动$ec到 stdin (即使 stdin 成为 fd 的副本$ec,然后关闭 fd $ec)。shell 现在将其 stdin 连接到进程替换,并继续从那里读取输入。但ruby可能已经阅读了所有内容,管道只会给出一个 EOF,退出外壳。

类似地,exec >&${gr}-(假设$gr不是 IFSbash拆分,因为您忘记了引号并且仍然在重定向中使用 split+glob)将 stdout 重定向到存储在$gr(closed $gr) 中的 fd 。任何进一步的常规输出,比如 fromls进入进程替换和grep. 所以,ls可能不会产生任何可见的输出,但echo hello应该。

您要修改的 fd 编号首先出现在重定向中,默认为 stdin ( 0) for<和 stdout ( 1) for >

  • @smac89,也不完全是这样。让我们看一下与第一个类似的东西。`exec {ec}&lt; &lt;(echo "echo bye")`。假设“ec”得到数字 9,只是为了选择一个。现在,fd 9 连接到进程替换。现在,不要对 `$ec` 执行任何其他操作,只需运行 `exec &lt;&amp;$ec-`,与 `exec 1&lt;&amp;9-` 相同。这表示将 9 移至 1 (stdin),因此现在 1 连接到进程替换,而 9 被关闭。然后 shell 从 1 读取输入,现在是进程替换。它读取“echo bye”,运行它,获取文件结尾,然后退出。 (2认同)