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--tac
argument reverses the order (as we want the last commands to be at the top), while--multi
allows 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? E-mail 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.