8

I frequently use Ctrl-D to exit interactive python sessions but sometimes I would accidentally hit it when the python session was not on. This will result in sending an EOF to the shell and subsequently closing it (without asking for confirmation). I have come to two solution from googling around:

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

The first option worked perfectly in my zsh shell and bash shell. However, the second option seems to only work in bash. When I'm in zsh, whatever number I set for IGNOREEOF, it sends EOF just like it was not set.

Can someone help with why ZSH behave this way or is it just the result of some peculiar env setup in my zsh shell?

3
  • IGNOREEOF isn't listed in the PARAMETERS USED BY THE SHELL section of zsh's man page, so I suspect your googled page simply wasn't correct about IGNOREEOF working in zsh.
    – mpy
    Aug 22, 2017 at 16:49
  • 2
    Here is a script to use zsh line editing to emulate bash's IGNOREEOF feature. Aug 22, 2017 at 17:26
  • Try setopt ignoreeof which is the zsh equivalent of the bash feature.
    – okapi
    Aug 31, 2017 at 9:17

2 Answers 2

9

Zsh does not use the IGNOREEOF parameter like Bash does. Instead, it is an option that you must set via the setopt builtin. From zshoptions(1):

IGNORE_EOF (-7)

Do not exit on end-of-file. Require the use of exit or logout instead. However, ten consecutive EOFs will cause the shell to exit anyway, to avoid the shell hanging if its tty goes away.

Also, if this option is set and the Zsh Line Editor is used, widgets implemented by shell functions can be bound to EOF (normally Control-D) without printing the normal warning message. This works only for normal widgets, not for completion widgets.

-- The second paragraph is important if you wish to emulate Bash's IGNOREEOF; see below

You can enable this option by adding the following to your shell configuration:

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

Emulating Bash (Optional)

If you would like to emulate the Bash behavior of being able to specify the number of Ctrl+D sequences before exiting the shell, then you can add the following ZLE widget definition* to your configuration:

# 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
}

Then, add the widget to ZLE and create a keybind for it:

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

You will still need to set the ignore_eof option however, otherwise Ctrl+D will ignore ZLE and immediately exit the shell regardless of this widget. Refer to the second paragraph of the man page snippet at the beginning of the answer.

* - Credit for this widget goes to its original author, Christoph Lange, and Bart Schaefer for his corrections

3
  • After doing setopt ignore_eof iterm2 freezes for a while @ZeroKnight
    – alper
    Jan 2, 2020 at 23:47
  • This function does not work. See superuser.com/a/1509672/586852 Jul 27, 2022 at 0:26
  • Zsh must have changed some behavior in the 4 years since this was written, as it worked then.
    – ZeroKnight
    Jul 27, 2022 at 8:19
3

I found the:

   zle send-break

and

    zle delete-char-or-list

cause LASTWIDGET to always be zle-line-init and not ever bash-ctrl-d, so the shell never ends. I had to remove those lines to have __BASH_IGNORE_EOF be decremented. As in:

# 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

I'm using zsh 5.1.1. thx, -m

1
  • This should be the correct answer! Jul 27, 2022 at 0:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .