为什么 zsh 描述符 10 连接到相同的 tty 时与 0/1/2 的偏移量不同?这有关系吗?

为什么 zsh 描述符 10 连接到相同的 tty 时与 0/1/2 的偏移量不同?这有关系吗?

为什么 zsh 描述符 10 连接到相同的 tty 时与 0/1/2 的偏移量不同?如果关闭 fd10 并立即将 fd0 复制到其中,会有什么影响吗?在 bash 上,等效的 255 与 fd0/1/2 具有相同的偏移量,这表明它与系统文件表中的条目相同。那么为什么 zsh 想要在系统文件表中拥有不同的条目呢?

COMMAND  PID      USER   FD   TYPE DEVICE  SIZE/OFF                NODE NAME
zsh     6980  codepoet    0u   CHR   16,2 0t1266790                 749 /dev/ttys002
zsh     6980  codepoet    1u   CHR   16,2 0t1266790                 749 /dev/ttys002
zsh     6980  codepoet    2u   CHR   16,2 0t1266790                 749 /dev/ttys002
zsh     6980  codepoet   10u   CHR   16,2    0t3349                 749 /dev/ttys002

答案1

如果你运行:

strace -e open,openat,fcntl,dup,dup2 zsh -f

或者您系统上的同等内容,您会看到:

openat(AT_FDCWD, "/dev/pts/2", O_RDWR|O_NOCTTY) = 3
fcntl(3, F_DUPFD, 10)                   = 10

zsh 已为 fd 10 重新打开 tty。

对于bash --norc,您会看到:

dup(2)                                  = 3
dup2(3, 255)                            = 255

bash 的 fd255 只是 fd2 的复制品。

大小/偏移量对于 tty 设备没有意义,我不知道这些值在您的系统上代表什么,但无论如何,它们不同的事实可以用 zsh 来解释, fd 10 指向不同的(新)打开文件描述在 bash 中,fd 0、1 或 2 上的 fd 255 指向相同的内容打开文件描述与FD 2一样。

这在实践中不会产生太大影响。

至于为什么zsh要重新打开tty设备,看代码1,是为了:

    /* Make sure the tty is opened read/write. */
    if (isatty(0)) {
        zsfree(ttystrname);
        if ((ttystrname = ztrdup(ttyname(0)))) {
            SHTTY = movefd(open(ttystrname, O_RDWR | O_NOCTTY));

注意仅当 stdin 和 stderr 都转到终端且不解释脚本时,POSIX shell 才是交互式的

如果存在 -i 选项,或者没有操作数并且 shell 的标准输入和标准错误附加到终端,则 shell 被认为是交互式的。

zsh 不需要 stderr 即可进入终端。

zsh的fd 10(实际上是9以上的第一个空闲的fd)与bash的fd 255(256以下的第一个空闲的fd)并不完全相同。 zsh 的行编辑器通常用于 I/O 和终端交互,而 bash 的仅用于 AFAICT 作业控制操作,并readline使用 stdin 进行输入,使用 stderr 进行输入回显,如果未打开 fd0 进行读取或使用,则 zsh 无法正常工作。 fd2 未打开用于写入。


1 该代码在 90 年代中期 2.5 之后的一段时间发生了变化。在此之前,建议SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR))您即使 stdin 不是终端也可以拥有一个交互式 shell,并且您在该 fd 上不会有不同的打开文件描述。实际上,/dev/tty对于作业控制交互来说,使用指向会话控制终端的指向比在 fd 0 或 2 上使用 tty(如 zsh 和 bash 目前所做的)更正确,即使在实践中这不太可能产生影响。

相关内容