# 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在管道命令之前被关闭。我哪里错了?
答案 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 3>&1
这将stdout复制到fd 3。
# 1: stdout.txt
# 2: stderr.txt
# 3: stdout.txt
当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怎么样?它还继承了父文件的描述符。
# Before
# 1: stdout.txt
# 2: stderr.txt
# 3: stdout.txt
grep bad 3>&-
fd 3没用,所以关闭了。
# After
# 1: stdout.txt
# 2: stderr.txt
# 3: [closed]
最后,父脚本关闭了现在不需要的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在这里实际上并不重要 - 如果没有这样做,代码也可以正常工作,因为ls
和grep
都不会对此文件描述符执行任何操作