管道和重定向理解

管道和重定向理解

请解释一下这个脚本(来自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

目前我想象它是如何工作的:

  1. 脚本将 fd/3 输出连接到 stdout
  2. 管道将 stdout 连接ls到 stdin grep(两个进程都继承 fd/3)
  3. 将 stderr 重定向ls到 stdout
  4. stdoutls更改为 fd/3 (因此grep进程没有更多ls输出,只有错误)
  5. fd/3 已关闭ls

这是重定向的确切顺序吗?

无法理解为什么我会看到lsif 没有错误的输出,并且我们关闭 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 而不是grepstdin。

顺序很重要,例如,如果我们运行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,这样它就不会被关闭”。

相关内容