3

I would like to create a key binding, using the key sequence C-x r, to reload the configuration of bash, stored in ~/.bashrc, and the one of the readline library stored in ~/.inputrc.

To reload the configuration of readline, I think I could use the re-read-init-file function which is described in man 3 readline:

re-read-init-file (C-x C-r)
        Read in the contents of the inputrc file, and incorporate any bindings or variable  assignments  found there.

To reload the configuration of bash, I could use the source or . command. However, I'm not sure what's the best way to combine a shell command with a readline function. So, I came up with the combination of 2 key bindings:

bind '"\C-xr":      ". ~/.bashrc \C-x\C-z1\C-m"'
bind '"\C-x\C-z1":  re-read-init-file'

When I hit C-x r in bash, here's what happens:

. ~/.bashrc    `~/.bashrc` is inserted on the command line
C-x C-z 1      `C-x C-z 1` is typed which is bound to `re-read-init-file`
C-m            `C-m` is hit which executes the current command line

It seems to work because, inside tmux, if I have 2 panes, one to edit ~/.inputrc or ~/.bashrc, the other with a shell, and I change a configuration file, after hitting C-x r in the shell, I can see the change taking effect (be it a new alias or a new key binding), without the need to close the pane to reopen a new shell.

But, is there a better way of achieving the same result? In particular, is it possible to execute the commands without leaving an entry in the history? Because if I hit C-p to recall the last executed command, I get . ~/.bashrc, while I would prefer to directly get the command which was executed before I re-sourced the shell configuration.

I have the same issue with zsh:

bindkey -s '^Xr' '. ~/.zshrc^M'

Again, after hitting C-x r, the command . ~/.zshrc is logged in the history. Is there a better way to re-source the config of zsh?

3

Don't inject a command into the command line to run it! That's very brittle — what you're trying assumes that there's nothing typed at the current prompt yet. Instead, bind the key to a shell command, rather than binding it to a line edition command.

In bash, use bind -x.

bind -x '"\C-xr": . ~/.bashrc'

If you also want to re-read the readline configuration, there's no non-kludgy way to mix readline commands and bash commands in a key binding. A kludgy way is to bind the key to a readline macro that contains two key sequences, one bound to the readline command you want to execute and one bound to the bash command.

bind '"\e[99i~": re-read-init-file'
bind -x '"\e[99b~": . ~/.bashrc'
bind '"\C-xr": "\e[99i~\e[99b~"'

In zsh, use zle -N to declare a function as a widget, then bindkey to bind that widget to a key.

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

In man bash, I found the HISTIGNORE environment variable, whose description is the following:

HISTIGNORE

        A  colon-separated list  of patterns  used to  decide which  command
        lines should be saved on the  history list. Each pattern is anchored
        at the  beginning of the line  and must match the  complete line (no
        implicit `*' is  appended). Each pattern is tested  against the line
        after the checks  specified by HISTCONTROL are  applied. In addition
        to the  normal shell  pattern matching  characters, `&'  matches the
        previous history  line. `&'  may be escaped  using a  backslash; the
        backslash  is removed  before  attempting a  match.  The second  and
        subsequent lines  of a multi-line  compound command are  not tested,
        and are added to the history regardless of the value of HISTIGNORE.

So, I exported the following value in ~/.bashrc:

bind '"\C-xr":   ". ~/.bashrc \C-x\C-z1\C-m"'
bind '"\C-x\C-z1":  re-read-init-file'

export HISTIGNORE="clear:history:. ~/.bashrc "

The last line should prevent bash from saving any clear, history and more importantly . ~/.bashrc command.


For zsh, I found the HIST_IGNORE_SPACE option, which is described in man zshoptions:

HIST_IGNORE_SPACE (-g)

        Remove command lines  from the history list when the  first character on
        the line  is a  space, or when  one of the  expanded aliases  contains a
        leading space. Only  normal aliases (not global or  suffix aliases) have
        this behaviour.  Note that the  command lingers in the  internal history
        until the  next command is entered  before it vanishes, allowing  you to
        briefly reuse or edit the line. If you want to make it vanish right away
        without entering another command, type a space and press return.

According to what it says, if this option is enabled, zsh should remove from the history any command beginning with a space. However, it temporarily stays in the internal history, until the next command is executed. So, I set this option in ~/.zshrc, and then redefined the key binding to re-source the configuration of the shell like so:

    setopt HIST_IGNORE_SPACE
    bindkey -s '^Xr' ' . ~/.zshrc^M ^M'
#                     │            │
#                     │            └─ command containing only a space to force `zsh`
#                     │               to “forget“ the previous command immediately
#                     └─ space added to prevent `zsh` from logging the command

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.