为什么 IGNOREEOF 在 Zsh 中不起作用?

为什么 IGNOREEOF 在 Zsh 中不起作用?

我经常使用 Ctrl-D 退出交互式 Python 会话,但有时我会在 Python 会话未开启时意外按下它。这将导致向 shell 发送 EOF 并随后关闭它(而不要求确认)。我通过谷歌搜索找到了两个解决方案:

  1. set -o ignoreeof
  2. export IGNOREEOF=10

第一个选项在我的 zsh shell 和 bash shell 中运行良好。但是,第二个选项似乎只在 bash 中有效。当我在 zsh 中时,无论我为 设定了什么数字IGNOREEOF,它都会发送 EOF,就像没有设定一样。

有人能帮我解释一下为什么 ZSH 会这样做吗?或者这只是我的 zsh shell 中某些特殊的环境设置造成的?

答案1

Zsh 不像 Bash 那样使用IGNOREEOF参数。相反,它是一个必须通过setopt内置命令设置的选项。来自zshoptions(1)

忽略 EOF (-7)

文件结束时不退出。要求使用 exit 或 logout。 但是,连续十次 EOF 都会导致 shell 退出,以避免当 tty 消失时 shell 挂起。

此外,如果设置了此选项并使用 Zsh 行编辑器,则由 shell 函数实现的小部件可以绑定到 EOF(通常是 Control-D),而不会打印正常的警告消息。这仅适用于普通小部件,不适用于完成小部件。

--如果你想模拟 Bash 的 IGNOREEOF,第二段很重要;见下文

您可以通过将以下内容添加到 shell 配置来启用此选项:

setopt ignore_eof    # Option names are case-insensitive and underscores are optional.

模拟 Bash(可选)

如果你想模拟 Bash 的行为,能够在退出 shell 之前指定Ctrl+序列的数量,那么你可以添加以下内容DZLE 小部件定义* 您的配置:

# Emulate Bash $IGNOREEOF behavior
bash-ctrl-d() {
  if [[ $CURSOR == 0 && -z $BUFFER ]]
  then
    [[ -z $IGNOREEOF || $IGNOREEOF == 0 ]] && exit
    if [[ $LASTWIDGET == bash-ctrl-d ]]
    then
      (( --__BASH_IGNORE_EOF <= 0 )) && exit
    else
      (( __BASH_IGNORE_EOF = IGNOREEOF-1 ))
    fi
    zle send-break
  else
    zle delete-char-or-list
  fi
}

然后,将小部件添加到 ZLE 并为其创建一个键绑定:

zle -N bash-ctrl-d
bindkey '^D' bash-ctrl-d

您仍然需要设置ignore_eof选项但是,否则Ctrl+D将忽略 ZLE 并立即退出 shell,而不管此小部件如何。请参阅答案开头的手册页片段的第二段。

* - 此小部件的原作者为 Christoph Lange,Bart Schaefer 对此进行了修改

答案2

我发现了:

   zle send-break

    zle delete-char-or-list

导致 LASTWIDGET 始终为 zle-line-init,而不是 bash-ctrl-d,因此 shell 永远不会结束。我必须删除这些行才能使 __BASH_IGNORE_EOF 递减。例如:

# 2x ctrl-d to exit ...
export IGNOREEOF=1

# bash like ctrl-d wrapper for IGNOREEOF
setopt ignore_eof
function bash-ctrl-d() {
  if [[ $CURSOR == 0 && -z $BUFFER ]]
  then
    [[ -z $IGNOREEOF || $IGNOREEOF == 0 ]] && exit
    if [[ "$LASTWIDGET" == "bash-ctrl-d" ]]
    then
      (( --__BASH_IGNORE_EOF <= 0 )) && exit
    else
      (( __BASH_IGNORE_EOF = IGNOREEOF ))
    fi
  fi
}
zle -N bash-ctrl-d
bindkey "^d" bash-ctrl-d

我正在使用 zsh 5.1.1。谢谢,-m

相关内容