49

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? Commented Jan 30, 2016 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
    Commented Jan 30, 2016 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
    Commented Jan 30, 2016 at 13:35

6 Answers 6

50

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
8
  • 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
    Commented Jan 30, 2016 at 3:15
  • 4
    You need to tweak WORDCHARS variable. In zsh it's easy vared WORDCHARS
    – appomsk
    Commented Jan 30, 2016 at 4:34
  • It would only be a duplicate if we matched it against an answered question in this forum. Commented Jan 30, 2016 at 12:19
  • 2
    @Jshura No, as per the question, I'd like two different functions, which is possible in bash.
    – Sparhawk
    Commented Jan 30, 2016 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
    Commented Dec 24, 2020 at 7:21
24

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

5
  • Brilliant! Thanks for taking the time to investigate and answer.
    – Sparhawk
    Commented Oct 30, 2016 at 10:00
  • Re Google: except I asked my question nine months ago, and they asked theirs less than a month ago.
    – Sparhawk
    Commented Oct 30, 2016 at 10:06
  • 1
    time is just a social construct man!.. but seriously, fair point. Commented Oct 10, 2019 at 13:43
  • Doesn't work for me. It seemingly makes ^w and meta-bs act in the same way.
    – conny
    Commented Aug 27, 2021 at 3:47
  • If this doesn't work for you, it may be because your WORDCHARS is empty, so perhaps you want to try setting it explicitly instead: local WORDCHARS='*?_-.[]~=&;!#$%^(){}<>' (from stackoverflow.com/a/11200998/4545777)
    – Cnly
    Commented Apr 16, 2022 at 10:44
10

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?

3

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
1

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.)

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

You must log in to answer this question.

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