第二行代码如何能够为grep而不是ls关闭fd 3?

时间:2018-03-14 15:09:56

标签: bash io

# Redirecting only stderr to a pipe.
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.

我正在查看https://www.tldp.org/LDP/abs/html/io-redirection.html,试图了解如何在bash中重定向输入和输出。我不明白第二行代码如何关闭fd 3 for grep'但不是ls。我理解的是ls的stderr被定向到stdout然后stdout被重定向到fd 3然后fd 3在管道命令之前被关闭。我哪里错了?

2 个答案:

答案 0 :(得分:1)

  

关闭'grep'的fd 3(但不是'ls')。

此评论错误。 fd 3对于两个命令都是关闭的,因为两个命令都有自己的3>&-

为什么脚本中有三个3>&-?这是因为ls和grep继承了所有父脚本文件描述符的副本。这三个进程中的每一个都有自己的fd 3,脚本会小心地关闭。没有必要关闭其中任何一个。这真的只是脚本作者格外小心 - 总是一件好事。

为了便于说明,假设脚本使用>stdout.txt 2>stderr.txt执行,因此stdout转到一个文件,stderr转到另一个文件。

# 1: stdout.txt
# 2: stderr.txt

现在让我们看看每个命令会发生什么。

EXEC

exec 3>&1

这将stdout复制到fd 3。

# 1: stdout.txt
# 2: stderr.txt
# 3: stdout.txt

LS

当ls forks继承父fds时,除了stdout首先被重定向到grep的管道。

# Before
# 1: [pipe]
# 2: stderr.txt
# 3: stdout.txt

ls -l 2>&1 >&3 3>&-

2>&1将stderr重定向到管道标准输出连接到,2: [pipe]。然后>&3将stdout重定向到fd 3,所以1: stdout.txt。然后3>&-关闭fd 3。

# After
# 1: stdout.txt
# 2: [pipe]
# 3: [closed]

的grep

那么grep怎么样?它还继承了父文件的描述符。

# Before
# 1: stdout.txt
# 2: stderr.txt
# 3: stdout.txt

grep bad 3>&-

fd 3没用,所以关闭了。

# After
# 1: stdout.txt
# 2: stderr.txt
# 3: [closed]

EXEC

最后,父脚本关闭了现在不需要的fd 3。

# Before
# 1: stdout.txt
# 2: stderr.txt
# 3: stdout.txt

exec 3>&-

# After
# 1: stdout.txt
# 2: stderr.txt
# 3: [closed]

答案 1 :(得分:0)

您的示例 ls关闭FD 3(与误导性评论文字相反),但在将FD 1作为副本之后。

exec 3>&1  # creates a backup of FD 1 on FD 3

# for ls:
# - stderr points to the pipe (which was stdout for the left-hand side before any
#   redirections).
# - stdout points to backup of prior stdout (copied from fd 3);
# - fd 3 is closed
ls -l 2>&1 >&3 3>&- \
 | grep bad 3>&-  # for grep:
                  # - stdin is the output from `ls -l` due to the pipeline
                  # - stderr is regular TTY stderr
                  # - fd 3 is closed

请注意,关闭FD 3在这里实际上并不重要 - 如果没有这样做,代码也可以正常工作,因为lsgrep都不会对此文件描述符执行任何操作