请解释一下这个脚本(来自ABSG。章。 20):
exec 3>&1 # Save current "value" of stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls').
# ^^^^ ^^^^
exec 3>&- # Now close it for the remainder of the script
目前我想象它是如何工作的:
- 脚本将 fd/3 输出连接到 stdout
- 管道将 stdout 连接
ls
到 stdingrep
(两个进程都继承 fd/3) - 将 stderr 重定向
ls
到 stdout - stdout
ls
更改为 fd/3 (因此grep
进程没有更多ls
输出,只有错误) - fd/3 已关闭
ls
这是重定向的确切顺序吗?
无法理解为什么我会看到ls
if 没有错误的输出,并且我们关闭 stdout 重定向的 fd/3 。
grep
关闭进程 ( )的 fd/3 的目的是什么grep bad **3>&-**
?
答案1
如果您认为文件描述符是接受文件作为值(或称其为 i/o 流)的变量,并且它们出现的顺序就是它们的求值顺序,那么这会有所帮助。
上面的例子中发生的情况是:
1) 脚本以以下内容开始(默认情况下,除非继承)
fd/0 = stdin # that's the keyboard
fd/1 = stdout # that's the screen
fd/2 = stderr # the screen again, but different stream
2)该exec
命令翻译为声明一个新变量并赋值
fd/3 = fd/1 # same as stdout
现在,两个文件描述符的值为 stdout,即两者都可以用于打印到屏幕。
3)beforels
执行并继承所有打开的文件描述符,发生以下设置
ls.fd/1 = grep.fd/0 # pipe gets precedence, ls.fd/1 writes to grep.stdin
ls.fd/2 = ls.fd/1 # ls.fd/2 writes to grep.stdin
ls.fd/1 = ls.fd/3 # ls.fd/1 writes to stdout
ls.fd/3 = closed # fd/3 will not be inherited by `ls`
fd/3 的目的是使标准输出值保持足够长的时间以将其返回到 fd/1。所以现在ls
发送到 fd/1 的所有内容都会发送到 stdout 而不是grep
stdin。
顺序很重要,例如,如果我们运行ls -l >&3 2>&1 3>&-
, ls.fd/2 将写入标准输出而不是grep
标准输入。
4) fd/3 forgrep
是封闭的,不被继承。无论如何它都会被使用。grep
只能过滤错误消息ls
ABSG 中提供的示例可能不是最有帮助的,并且评论“关闭“grep”的 fd 3(但不是“ls”)” 有点误导,你可以理解为:“对于 ls,在取消设置之前将 ls.fd/3 的值传递给 ls.fd/1,这样它就不会被关闭”。