Tiny clipboard management in bash

Florent Teissier
3 min readJun 25, 2019

In a previous article I spoke about how I configured my machine, and I talked about an awesome little program called dmenu. Here is how you can use it to build a very simple clipboard history management in very few lines of code.
The goal of this script is to be able to browse the history of every thing you recently copy/paste. It can be very useful when you copied several things and you want to paste again something that is not in your clipboard anymore.

Dmenu

Dmenu strictly follow the Unix philosophy: it does one thing, and it does it well. It simply takes standard input and prompt a graphical menu and print to standard output the selected item. The menu it displays is very basic but it let you select your choice with your keyboard. You can use arrows keys or ctrl-p/ctrl-n. You can even filter out by typing the first letters of your choice and hit enter. It has some options, so you can customize the colors and other stuff.

dmenu in action

You can also choose to display the menu vertically with the option -l.

Writing the script

I took a basic approach:

First I need a script that record every text I copy to the clipboard and save it into a plain file. The script simply checks the content of xclip and append it to the file it is not already in. I chose to keep track of the last 5 items copied.
I can’t use crontab to run the script every second, because the minimum frequency you can run your script in with crontab is 1 minute.
So I had to use an infinite loop with `sleep 1` to run it every second.

#!/bin/bashMAX_SIZE=5
HISTORY_FILE=~/.copy-history
function main() {
createHistoryFile
while true
do
clip=$(xclip -o -selection clipboard)
if [ “$(grep -c “$clip” “$HISTORY_FILE”)” = 0 ]; then
echo “$clip” >> “$HISTORY_FILE”
nbLines=$(wc -l “$HISTORY_FILE” | cut -d ‘ ‘ -f1)
if [ “$nbLines” -gt “$MAX_SIZE” ]; then
sed -i ‘1d’ “$HISTORY_FILE”
fi
fi
sleep 1
done
}
function createHistoryFile() {
if [ ! -f $HISTORY_FILE ]; then
touch $HISTORY_FILE
fi
}
main

I launch the script in my i3 config

exec — no-startup-id ~/bin/copy-history &

There may be a way to trigger a callback every time you copy so you don’t check every second for nothing but i’m not aware of it.

The second step is to write a script that read the content of the history file and feed it to dmenu and copy the selected item.

#!/bin/bash
CHOICE=$(tac ~/.copy-history | dmenu -l 10)
echo “$CHOICE” | xclip -selection c

Finally I set up a keyboard shortcut in my i3 config to trigger it.

bindsym $mod+slash exec ~/bin/history-dmenu
The script in action

Improvements

It’s a very basic and naive implementation. The next step is to handle multi-lines copied text. But I think it demonstrates how easily you can build cool and useful tool with few lines of code.

--

--