Since fish 3.6, abbr can be used for a nice replacement for bash's history substitution features.
For just !!
:
function last_history_item; echo $history[1]; end
abbr -a !! --position anywhere --function last_history_item
The rest of this article is outdated and should be rewritten.
I tried, I really tried to give up bash's history substitution. For the most part, I'm successful, but the 'sudo !!' and 'mkdir ...; cd !$' habits are really strong.
So, while I still use fish's vastly improved command line editing features, I did set up the following:
> funced fish_user_key_bindings
function bind_bang
switch (commandline -t)
case "!"
commandline -t -- $history[1]
commandline -f repaint
case "*"
commandline -i !
end
end
function bind_dollar
switch (commandline -t)
# Variation on the original, vanilla "!" case
# ===========================================
#
# If the `!$` is preceded by text, search backward for tokens that
# contain that text as a substring. E.g., if we'd previously run
#
# git checkout -b a_feature_branch
# git checkout main
#
# then the `fea!$` in the following would be replaced with
# `a_feature_branch`
#
# git branch -d fea!$
#
# and our command line would look like
#
# git branch -d a_feature_branch
#
case "*!"
commandline -f backward-delete-char history-token-search-backward
case "*"
commandline -i '$'
end
end
function fish_user_key_bindings
bind ! bind_bang
bind '$' bind_dollar
end
> funcsave bind_bang bind_dollar fish_user_key_bindings
The upshot is that !! gets replaced by the previous command, and that !$ gets replaced by the previous command's last argument.
On the one hand, this is far from complete history substitution, just the two features thereof that account for 95% of its use.
On the other hand, it's superior to Bash history substitution in that the replaced text is added immediately to the current command line, and can be edited.
alternative
bind \cs 'commandline "sudo $history[1]"'
note the single quote is necessary to prevent $
substitution from occurring immediately
!$
is provided already by the alt+.
keybind. in fish 2.3 you can press escape+.
.
Abbr based solution for !! (since 2.2.0)
This runs as a hook after every command and make/replace the abbr !! with "sudo last ran command". Then you can just run this abbr by typing !!<RET>
or let it expand by typing !!<SPC>
.
function sudobangbang --on-event fish_postexec
abbr -g !! sudo $argv[1]
end
Note for vi or hybrid mode
If you are running vi or hybrid mode, you'll need to specify insert mode in the bindings within the fish_user_key_bindings
file, for example:
function fish_user_key_bindings
fish_hybrid_key_bindings
bind -M insert ! bind_bang
bind -M insert '$' bind_dollar
end
getting
and $?
These will substitute the correct fish versions of these concepts without you having to type another command.
# enables $?
function bind_status
commandline -i (echo '$status')
end
# enables $$
function bind_self
commandline -i (echo '$fish_pid')
end
# enable keybindings
function fish_user_key_bindings
bind '$?' bind_status
bind '$$' bind_self
end
Fish - The friendly interactive shell