41

Bash behaviour

I've just migrated from bash to zsh. In bash, I had the following line in ~/.inputrc.

"\e\C-?": unix-filename-rubout

Hence, Alt+Backspace would delete back to the previous slash, which was useful for editing paths.

Separately, bash defaults to making Ctrl+w delete to the previous space, which is useful for deleting whole arguments (presuming they don't have spaces). Hence, there two slightly different actions performed with each key combination.

Zsh behaviour

In zsh, both Alt+Backspace and Ctrl+w do the same thing. They both delete the previous word, but they are too liberal with what constitutes a word-break, deleting up to the previous - or _. Is there a way to make zsh behave similarly to bash, with two independent actions? If it's important, I have oh-my-zsh installed.

3
  • 1
    Do you want to change zsh's definition of what constitutes a word? If so: unix.stackexchange.com/questions/48577/… Or do you want to define a new command with a different definition of word? Jan 30 '16 at 13:22
  • @Gilles I guess a combination of both. In bash, I'd use the two distinct commands regularly: i.e. delete to the last / and delete to the last ` `. They have different functions.
    – Sparhawk
    Jan 30 '16 at 13:24
  • 1
    @Gilles So yes, that link works for my bash-like Alt+Backspace behaviour, but I'd still like the (different) bash-like Ctrl+w behaviour, i.e. delete to last space.
    – Sparhawk
    Jan 30 '16 at 13:35
37

A similar question was asked here: zsh: stop backward-kill-word on directory delimiter

and a workable solution given: add these settings to your zshrc:

autoload -U select-word-style
select-word-style bash
7
  • 1
    Thanks for the answer. However, none of those answers work for me. (Specifically, the one you quoted makes no change.) Possibly, it's because I have oh-my-zsh installed. In any case, this doesn't seem to address the two different functions and key bindings as per my question. (And if my question were it dupe it should be closed as a dupe. Which it is not.)
    – Sparhawk
    Jan 30 '16 at 3:15
  • 3
    You need to tweak WORDCHARS variable. In zsh it's easy vared WORDCHARS
    – Jshura
    Jan 30 '16 at 4:34
  • It would only be a duplicate if we matched it against an answered question in this forum. Jan 30 '16 at 12:19
  • 2
    @Jshura No, as per the question, I'd like two different functions, which is possible in bash.
    – Sparhawk
    Jan 30 '16 at 13:28
  • 1
    worked great for me on my mac (bash to zsh). Key bindings can be defined in the preferences of the terminal app
    – Thomas
    Dec 24 '20 at 7:21
21

Edit: The next google result after your question was this one with same solution : zsh: make ALT+BACKSPACE stop at non-alphanumeric characters

This answer was provided by /nick FoH from #zsh on freenode.

backward-kill-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle backward-kill-word
    zle -f kill
}
zle -N backward-kill-dir
bindkey '^[^?' backward-kill-dir

This way you can use ctrl+w for deleting a Word (in vim lingo) and alt+bkspc to delete a word

4
  • Brilliant! Thanks for taking the time to investigate and answer.
    – Sparhawk
    Oct 30 '16 at 10:00
  • Re Google: except I asked my question nine months ago, and they asked theirs less than a month ago.
    – Sparhawk
    Oct 30 '16 at 10:06
  • 1
    time is just a social construct man!.. but seriously, fair point. Oct 10 '19 at 13:43
  • Doesn't work for me. It seemingly makes ^w and meta-bs act in the same way.
    – conny
    Aug 27 '21 at 3:47
9

Expanding on JunkMechanic's answer, I wanted that

  • existing zsh shortcuts (CtrlW, Ctrl and Ctrl) works as in zsh defaults
  • Alt-based shortcuts (AltW, Alt and Alt) work similarly, but "finer grained", e.g. up to the closest /

Here's what I use now:

# Alt+Backspace
backward-kill-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle backward-kill-word
    zle -f kill  # Ensures that after repeated backward-kill-dir, Ctrl+Y will restore all of them.
}
zle -N backward-kill-dir
bindkey '^[^?' backward-kill-dir


# Alt+Left
backward-word-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle backward-word
}
zle -N backward-word-dir
bindkey "^[[1;3D" backward-word-dir

# Alt+Right
forward-word-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle forward-word
}
zle -N forward-word-dir
bindkey "^[[1;3C" forward-word-dir

For details on the zle -f kill, see Zsh - pasting text killed in a custom widget only works for last word, can that be fixed?

2

I achieved your desired result by sticking the following in $ZDOTDIR/.zshrc:

# Use bash-like word definitions for navigation and operations
autoload -Uz select-word-style
select-word-style bash

# Use C-w to kill back to the previous space
zle -N backward-kill-space-word backward-kill-word-match
zstyle :zle:backward-kill-space-word word-style space
bindkey '^W' backward-kill-space-word

This has an advantage over other answers by not limiting the target delimiter of Alt+Backspace to /; for example, it will delete back to -, as well. Still, Ctrl+w will delete back to the previous space. This is more bash-like than other answers.

I am using zsh 5.8 on macOS, without oh-my-zsh or any other configuration framework.

Reference: http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#index-backward_002dkill_002dword_002dmatch


Bonus: The following makes zsh even more bash-like:

# Use C-u to kill to the beginning of the line
bindkey '^U' backward-kill-line

# Use C-x C-e to edit the current command line in $VISUAL
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line
0

Just wanted to add this in nh2's answer

  • alt + left/right arrow to move
  • alt + delete/w for deleting word forward/backward

# Alt+Delete
forward-kill-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle kill-word
}
zle -N forward-kill-dir
bindkey '^[[3;3~' forward-kill-dir

# Alt+w
backward-kill-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle backward-kill-word
}
zle -N backward-kill-dir
bindkey '^[w' backward-kill-dir

# Alt+Left
backward-word-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle backward-word
}
zle -N backward-word-dir
bindkey "^[[1;3D" backward-word-dir

# Alt+Right
forward-word-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle forward-word
}
zle -N forward-word-dir
bindkey "^[[1;3C" forward-word-dir
0

bindkey '^[^?' vi-backward-kill-word


As far as I can tell, its effect on Meta-BackSpace is the same as with the answer suggested by @thomas-dickey, and it's a oneliner rather than two ;-). However, this only affects Meta-BS. If you are looking for the full bash-like behavior with Meta-(Left/Right) navigation then select-word-style is the right way.

(Footnote: the select-word-style-thing is documented in man zshcontrib but they are all but incomprehensible to me. vi-backward-kill-word is documented in man zshzle.)

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.