Bash:文件描述符

Rob*_*ino 15 bash

我是Bash的初学者,但我正在努力学习这个工具,以便在这些日子里找到一份计算机工作.

我现在正在尝试自学文件描述符.让我分享一些我的实验:


#!/bin/bash

# Some dummy multi-line content
read -d '' colours <<- 'EOF'
        red
        green
        blue
EOF

# File descriptor 3 produces colours
exec 3< <(echo "$colours")

# File descriptor 4 filters colours
exec 4> >(grep --color=never green)

# File descriptor 5 is an unlimited supply of violet
exec 5< <(yes violet)

echo Reading colours from file descriptor 3...
cat <&3
echo ... done.

echo Reading colours from file descriptor 3 again...
cat <&3
echo ... done.

echo Filtering colours through file descriptor 4...
echo "$colours" >&4
echo ... done. # Race condition?

echo Dipping into some violet...
head <&5
echo ... done.

echo Dipping into some more violet...
head <&5
echo ... done.
Run Code Online (Sandbox Code Playgroud)

当我看到来自上面的输出时,有些问题浮现在脑海中:

  1. fd3似乎在"消费"后"耗尽",是否在首次使用后自动关闭?
  2. fd3与命名管道有什么不同?(我已经看过的东西)
  3. 正好没有命令yes开始执行?在fd宣言?后来?
  4. yes停止(CTRL-Z或其他),并需要更多的紫色时重新启动?
  5. 我怎样才能获得PID yes
  6. 我可以获得"活跃"fds列表吗?
  7. 通过fd4过滤非常有趣的竞争条件,可以避免吗?
  8. yes只有当我停下exec 5>&-
  9. 我是否关闭>&-或是否关闭<&-

我现在就到此为止.

谢谢!

PS:部分(编号)的答案很好..我会把自己的不同部分放在一起..(虽然一个人的综合答案会令人印象深刻!)

Cel*_*ada 15

fd3似乎在"消费"后"耗尽",是否在首次使用后自动关闭?

不,它没有关闭.这是由于exec工作方式.在您使用exec(不带参数)的模式中,其功能是按照指定给自身的I/O重定向的要求排列shell自己的文件描述符,然后将它们保留,直到脚本终止或再次更改为止后来.

稍后,cat在其标准输入(文件描述符0)上接收该文件描述符3的副本.退出cat时隐式关闭标准输入cat(或者,尽管不太可能,cat但在它存在之前将其关闭,但这并不重要).此文件的原始副本(shell的文件描述符3)仍然存在.虽然实际文件已达到EOF,但不会再从中读取任何内容.

fd3与命名管道有什么不同?(我已经看过的东西)

shell的<(some command)语法(这不是标准的bourne shell语法,我相信只有zshand bash,顺便说一句)可能实际上是使用命名管道实现的.它可能不在Linux之下,因为有更好的方法(使用/dev/fd),但它可能在其他操作系统上.

所以从这个意义上讲,这种语法可能也可能不是设置命名管道的帮助器.

什么时候命令是开始执行?在fd宣言?后来?

一旦<(yes violet)构造被评估(在exec 5< <(yes violet)评估时发生).

肯定停止(CTRL-Z或其他)并在需要更多紫罗兰时重新启动?

不,它不会停止.但是,当它开始产生的输出比读取管道另一端正在消耗的任何东西时,它将很快阻止.换句话说,管道缓冲区将变满.

我怎么能得到是的PID?

好问题!执行$!后似乎立即包含它yes.然而,似乎有一个中间子shell,你实际上得到了该子shell的pid.尽量<(exec yes violet)避免中间过程.

我可以获得"活跃"fds列表吗?

不是来自shell.但是,如果你使用像Linux这样的操作系统/proc,你可以咨询/proc/self/fd.

通过fd4过滤非常有趣的竞争条件,可以避免吗?

为避免这种情况,您可能希望grep在继续执行脚本之前等待该过程完成.如果您获得该流程的流程ID(如上所述),我认为您应该能够获得该流程wait.

只有当我执行5>& - 时才会停止

是.接下来会发生的是yes将继续尝试永久产生输出,但是当文件描述符的另一端关闭时,它将获得写入错误(EPIPE)或SIGPIPE默认情况下致命的信号().

是否与>& - 或<& - ?关闭是否重要?

不可以.两种语法都是为了一致性而提供的.