2

I'm using zsh version 5.3.1:

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

I'm trying to define a key binding, using the key sequence C-x r, to reload the configuration of zsh. Thanks to @Gilles, I included this code in my ~/.zshrc:

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

It works, except that when I hit C-x r, zsh complains with the errors:

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

I can reproduce these errors with the following minimal zshrc:

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

reread_zshrc () {
. ~/.zshrc
}

zle -N reread_zshrc
bindkey '^Xr' reread_zshrc

Here are the reasons why I included the 2 stty commands, and the dircolors command in my zshrc.

stty -ixon prevents the terminal driver from interpreting C-s and C-q as terminal flow controls: by default, C-s freezes the terminal and C-q unfreeze it. It allows to use C-s and C-q in key bindings for the shell or the text editor, without freezing the terminal.

stty quit undef prevents the terminal driver from sending the SIGQUIT signal when C-\ is pressed. Again, it allows to use this key in a key binding without the foreground process to quit.

eval "$(dircolors -b ~/.dircolors)" asks the ls command to read its configuration from ~/.dircolors. It allows to customize the colors from the output of a ls command.

I suppose I need to protect these 3 lines from being re-sourced by zsh if they've already been executed in the current shell. But I don't know which condition to write:

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

Besides, I would like to better understand these error messages, because if I execute them in an interactive zsh shell, they don't cause any issue. Why do they only raise errors from this key binding.

  • 1
    Try changing . ~/.zshrc to . ~/.zshrc < /dev/tty – Stéphane Chazelas Jun 11 '17 at 12:38
  • @StéphaneChazelas Thank you very much. It seems to work perfectly. I don't have any error messages, and the configuration is properly re-sourced. If you post it as an answer, I'll accept it. – user547381 Jun 11 '17 at 12:41
4

In zle widgets, it seems zsh closes stdin. I suppose zsh wants to avoid commands in those widgets interfering directly with user input, but it would be more sensible to redirect stdin from /dev/null instead (that will be fixed in the next release).

When stdin (file descriptor 0) is closed, that means the first file a command opens becomes its stdin (as file descriptors are allocated from the first free one).

In dircolors, that triggers a bug. dircolors opens your ~/.dircolors, and then tries to make it its stdin without noticing it was already its stdin (because that's the fd open() returns). So, the dup2(0,0) (dup stdin onto itself) fails with a EBADF error which dircolors reports.

stty sets the settings of the terminal open on its stdin. Here, stdin is closed, so stty returns with an error.

Here, you can change your widget so it restores stdin to the terminal:

reread_zshrc () . ~/.zshrc < $TTY

But note that changing the tty settings from within a zle widget (though I don't know what your stty command does) is a bad idea as zle sets the tty in a special mode for line editing which you don't want to mess up with (and at the end of editing, the normal tty settings will be restored anyway, so the changes you're making will be lost).

So maybe instead you should make stdin /dev/null (as you don't really want to be doing things with the terminal there), but stty would still complain (as /dev/null is not a tty device), so you may also want to redirect stderr to /dev/null to hide those error messages (though it would hide all error messages):

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.