更正 shell 提示的 fd

Joz*_*erc 1 c unix shell file-descriptor

我正在用 C 制作一个自定义 shell,我想知道我应该在哪个 fd 上写我的提示。

mycoolshell $
Run Code Online (Sandbox Code Playgroud)

查看其他经典 shell,我发现它dash使用 STDERR 作为提示。cshtcsh使用标准输出。对于bash,zsh和 BSDsh我找不到任何东西。我用了

mycoolshell $
Run Code Online (Sandbox Code Playgroud)

检查 dash 的提示 fd。与 csh with 相同,csh 1>file但我对其他的不走运。

是否有标准或 POSIX fd 用于此?可以使用 STDIN 吗?

ric*_*ici 5

如果您希望与 Posix 兼容,则需要将提示写入stderr. (请参阅PS1下面的环境变量规范。)

不管严格的 Posix 兼容性,stdin肯定是不正确的,因为它可能不允许写操作。stdout也不是一个好主意,因为它通常是行缓冲的。一些 shell(包括zsh,我相信)将提示写入连接到当前终端(例如/dev/tty)的文件描述符,这可能stderr是打开的,好像没有重定向一样,尽管它不一定是相同的文件描述符。但是使用/dev/tty或等效是非标准的。

只有当 shell 是交互式的时才会打印提示。根据 Posix 的说法,如果 shell 以以下两种方式之一调用,则它是交互式的:

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

显然,如果您使用 shell 来执行脚本,您不希望 shell 发出提示。所以你需要一些机制来判断 shell 是被交互使用还是作为脚本处理器使用;Posix 的要求似乎相当准确。(请参阅isatty()库函数以了解进行此测试的一种方法。)

这也说明了为什么您的测试在stderr重定向到文件时未能捕获提示。重定向stderr会导致 shell 不具有交互性,因此不会出现提示。要正确进行测试,您需要使用该-i选项强制 shell 交互。

Posix 要求可以通过更改PS1环境变量的值来修改提示。这就是 Posix 所说的,包括要求将提示打印到stderr:(强调添加)

PS1

每次交互式 shell 准备好读取命令时,该变量的值应进行参数扩展并写入标准错误。默认值应为“$”。对于具有特定附加实现定义权限的用户,默认值可能是另一个实现定义的值。shell 将替换字符 '!' 的每个实例 在 PS1 中,下一个要键入的命令的历史文件号。逃避“!” 和另外一个 '!' (即, "!!" )应放置文字字符 '!' 在提示中。(Shell 命令语言,Shell 变量

大多数 shell 允许在PS1. 但该值受参数扩展影响的事实允许进行广泛的定制。这意味着(与通常的变量扩展不同)出现在PS1变量值中的参数和命令引用在每次打印提示时都会被扩展。