Copying previous commands with fzf and zsh
Jul 14, 2022
Sometimes I want to copy a command I previously typed in my shell to the clipboard. It may be for documentation, note-taking, writing a script, setting up an Ansible playbook, sending to someone… You name it.
While I could always search the terminal window for it and select it, I have set up an alias that makes things much easier and less error-prone:
alias hy="
fc -ln 0 |
awk '!a[\$0]++' |
fzf --tac --multi --header 'Copy history' |
xsel --clipboard
"
This will perform the task silently. If you prefer a confirmation message after each copy, a clean approach is to convert the alias into a function like this:
hy() {
local -r entry="$(fc -ln 0 | awk '!a[$0]++' | fzf --tac --multi --header 'Copy history')"
[[ -n "$entry" ]] && xsel --clipboard <<< "$entry" >/dev/null && echo "Copied to clipboard." >&2
}
Until now, we assumed the system was running on X11. Now, let’s make it work on Wayland too:
hy() {
local copy_cmd
case "$XDG_SESSION_TYPE" in
x11) copy_cmd="xsel --clipboard" ;;
wayland) copy_cmd="wl-copy" ;;
*) echo "Session type not detected."; return ;;
esac
local -r entry="$(fc -ln 0 | awk '!a[$0]++' | fzf --tac --multi --header 'Copy history')"
[[ -n "$entry" ]] && eval $copy_cmd <<< "$entry" >/dev/null && echo "Copied to clipboard." >&2
}
In action
Typing hy (short for “history yank”) brings fzf with a list of your most recent commands. You can browse them using the keyboard or perform a fuzzy search. Pressing Enter copies the selected command to the clipboard.
Even better, if you enable multi-selection on fzf, you can select multiple commands using Tab. They will be copied to the clipboard one per line.
The how
Explaining each part:
fc -ln 0: On zsh, this returns the entire shell history, one command per line. If you use Bash or another shell, just replace it with the equivalent command.awk '!a[\$0]++': The history is piped to awk, which removes duplicate entries. Without this cleaning, fzf may display multiple repeated lines, which can be annoying.fzf --tac --header 'Copy history': The result is piped to fzf. The--tacargument reverses the order (as we want the last commands to be at the top), while--multiallows multiple selection. We also add a prompt message using--header.wl-copy(on Wayland) orxsel --clipboard(on X11): Finally, the commands selected are copied to the clipboard.
Needless to say, be sure to have the mentioned tools installed on your system for this to work.
Have comments? Email me.
This post was updated:
- Feb 25, 2024: Add implementation to print a confirmation message.
- Feb 25, 2024: Replace xclip with xsel.
- Jul 26, 2024: Add Wayland support.