为什么 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 目前所做的)更正确,即使在实践中这不太可能产生影响。