如何测试当前 zsh shell 是否已经执行了 `dircolors` 和 `stty` 命令?

如何测试当前 zsh shell 是否已经执行了 `dircolors` 和 `stty` 命令?

我使用的是zsh5.3.1版本:

% zsh --version
zsh 5.3.1 (x86_64-pc-linux-gnu)

我正在尝试使用键序列定义键绑定,C-x r以重新加载 的配置zsh。谢谢@吉尔斯,我将此代码包含在我的~/.zshrc

reread_zshrc () {
. ~/.zshrc
}
zle -N reread_zshrc
bindkey '^Xr' reread_zshrc

它有效,除了当我点击 时C-x rzsh抱怨错误:

stty: 'standard input': Bad file descriptor
stty: 'standard input': Bad file descriptor
dircolors: /home/user/.dircolors: Bad file descriptor

我可以用以下最少的内容重现这些错误zshrc

stty -ixon
stty quit undef
eval "$(dircolors -b ~/.dircolors)"

reread_zshrc () {
. ~/.zshrc
}

zle -N reread_zshrc
bindkey '^Xr' reread_zshrc

以下是我包含这 2 个stty命令以及该dircolors命令在我的zshrc.

stty -ixon防止终端驱动程序解释C-sC-q作为终端流控制:默认情况下,C-s冻结终端并C-q解冻它。它允许在 shell 或文本编辑器的键绑定中使用C-sC-q,而无需冻结终端。

stty quit undef防止终端驱动程序SIGQUITC-\按下 时发送信号。同样,它允许在键绑定中使用此键,而无需退出前台进程。

eval "$(dircolors -b ~/.dircolors)"要求ls命令从 读取其配置~/.dircolors。它允许根据命令的输出自定义颜色ls

zsh我想如果这 3 行已经在当前 shell 中执行过,我需要保护它们不被重新分配。但我不知道该写哪个条件:

if <stty and dircolors haven't been executed already>; then
  stty -ixon
  stty quit undef
  eval "$(dircolors -b ~/.dircolors)"
if

此外,我想更好地理解这些错误消息,因为如果我在交互式zshshell 中执行它们,它们不会导致任何问题。为什么他们只从这个键绑定中引发错误。

答案1

zle小部件中,它似乎zsh关闭了标准输入。我zsh想避免这些小部件中的命令直接干扰用户输入,但从 /dev/null 重定向 stdin 会更明智(这将在下一个版本中修复)。

当标准输入(文件描述符 0)关闭时,这意味着命令打开的第一个文件将成为其标准输入(因为文件描述符是从第一个空闲文件分配的)。

在 中dircolors,这会触发一个错误。dircolors打开您的~/.dircolors,然后尝试将其设为标准输入,而不会注意到它已经是其标准输入(因为那是 fdopen()返回的)。因此,dup2(0,0)(将 stdin 复制到自身上)失败并报告 EBADF 错误dircolors

stty设置在其标准输入上打开的终端的设置。此处,stdin 已关闭,因此stty返回错误。

在这里,您可以更改您的小部件,以便它将标准输入恢复到终端:

reread_zshrc () . ~/.zshrc < $TTY

但请注意,从小部件内更改 tty 设置zle(尽管我不知道您的stty命令的作用)是一个坏主意,因为zle将 tty 设置为特殊模式以进行行编辑,您不想弄乱它(并且在编辑结束时,无论如何都会恢复正常的 tty 设置,因此您所做的更改将会丢失)。

所以也许你应该制作 stdin /dev/null(因为你真的不想在那里用终端做事),但stty仍然会抱怨(因为/dev/null不是 tty 设备),所以你可能还想将 stderr 重定向到 /dev/ null 来隐藏这些错误消息(尽管它会隐藏全部错误消息):

reread_zshrc() . ~/.zshrc < /dev/null 2> /dev/null

相关内容