我正在读一本关于 Linux 命令行的书,其中作者似乎没有遵循 bash 手册中有关重定向操作中使用的箭头符号的约定。也就是说,<
无论描述符是输入描述符还是输出描述符,他总是使用向左箭头来复制和关闭文件描述符。
这是一个例子:
exec 3<&0 4<&1 #shouldn't be 4>&1 ?
#...
exec 3<&- 4<&- #shouldn't be 4>&- ?
Bash 手册页在这一点上含糊其辞,根据它,复制/关闭和移动文件描述符具有以下语法:
#Duplicating and closing (in case word expands to -):
[n]<&word
[n]>&word
#Moving:
[n]<&digit-
[n]>&digit-
仅当我们不明确提供n
.但是当我们这样做时,是否意味着我们可以互换使用这些形式?
答案1
这并不重要,因为 和 都4>&1
做4<&1
同样的事情:dup2(1, 4)
这是将一个 fd 复制到另一个 fd 的系统调用。复制的fd自动继承原始fd的I/O方向。 (与4>&-
vs相同4<&-
,两者都解析为close(4)
,并且后面跟着4>&1-
)。dup2(1, 4)
close(1)
然而,4<&1
语法很令人困惑,除非由于某种原因 fd 1 明确开放供阅读(这会更令人困惑),所以在我看来应该避免。
重复的fd
共享相同打开文件描述这意味着它们在文件中共享相同的偏移量(对于那些有意义的文件类型)和相同的关联标志(I/O 重定向/打开模式、O_APPEND 等)。
在Linux上,还有另一种方法复制a fd
(这并不是真正的重复)并创建一个新的打开文件描述对于相同的资源但可能具有不同的标志。
exec 3> /dev/fd/4
在 Solaris 和可能大多数其他 Unices 上,这或多或少相当于dup2(4, 3)
在 Linux 上,它打开与 fd 4 从头开始指向的相同资源。
这是一个重要的区别,因为例如,对于常规文件,fd 3 的偏移量将为 0(文件的开头)并且文件将被截断(这就是为什么在 Linux 上您需要编写tee -a /dev/stderr
而不是tee /dev/stderr
)。
并且I/O模式可以不同。
有趣的是,如果 fd 4 指向管道的读取端,那么 fd 3 现在指向写入端(/dev/fd/3
行为类似于命名管道):
$ echo a+a | { echo a-a > /dev/fd/0; tr a b; }
b+b
b-b
$ echo a+a | { echo a-a >&0; tr a b; }
bash: echo: write error: Bad file descriptor
b+b