Copying previous commands with fzf and zsh

Sometimes I want to copy a command I previously typed on 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 make 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 want a confirmation message after each copy, a clean way is to convert the alias to 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

The alias in action.

Typing hy (short for “history yank”) brings fzf with the last commands I typed. I can browse them with the keyboard or use the fuzzy search. Pressing enter will copy the selection to the clipboard.

Better yet, as I have multi-selection enable on fzf, I can select multiple commands using tab. They are copied 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 other shell, just replace it with the equivalent command.
  • awk '!a[\$0]++': The history is piped to awk, which removes the duplicates. 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: 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) or xsel --clipboard (on X11): Finally, the commands we selected are copied to the clipboard.

Needless to say, be sure to have the mentioned tools installed on your system for this to work.


Updates

  • : Add implementation to print a confirmation message.
  • : Replace xclip with xsel.
  • : Add Wayland support.

  • All posts · Show comments