in hardware, software

How to automatically run a script after inserting a USB device on Ubuntu?

Here’s the setup: you have a computer which has a SD port (small memory cards, mostly used in cameras, phones, etc.). You want to get all of your photos from that card automatically as soon as you insert your card (may be a USB key as well), that is, run a script which will search for all of your photos, and copy them to a local directory.

I know, some programs already do this, but they require Xwindow and some ugly Gnome/KDE app. What we’re doing here is a minimal setup, using the least memory.

Normally, on a normal Unix system you would use the included device detection mechanism, which is hotplug. But on Ubuntu (at least Gutsy and Hardy), the de-facto/required way is by using udev, which is an event based system, using rules to fire new events/mount/symlink or run programs according to some patterns defined as “rules”.

So, the first thing to do is to identify your device according to USB events. udevinfo is your friend. So, after looking at the output of dmesg, you’ll see your USB device is available on some sd* device.

So run:
udevinfo -a -p /sys/block/sda
(replace sda with you device)

You will get a list of “blocks” representing each layer of drivers. For example:

[email protected]:/etc/udev/rules.d# udevinfo -a -p /sys/block/sda/

looking at device '/block/sda':
ATTR{stat}==" 229567 [...] 456048 3697068"

looking at parent device '/devices/pci0000:00/00[...]:
ATTRS{model}=="ST3250310AS "
ATTRS{vendor}=="ATA "

These are in fact attributes that you can use in your rule to filter the devices. So for example,
to run a shell script when a SCSI device is detected which has a size of 1GB, I’ll use the following line:

KERNEL=="sd?1", ATTRS{size}=="1999872", RUN+="/usr/local/bin/"

This line is to be put in a new file in /etc/udev/rules.d, named something like 91-backuptousbdrivetrigger.rules. It’s better to put the file at the end of the rules (the “91”), as not to disturb other module loadings.

The content of the file can be:


if [ "${ACTION}" = "add" ]; then
rm -rf /tmp/x
mkdir /tmp/x
mount -t vfat /dev/sdc1 /tmp/x
find /tmp/x -name "*jpg" -exec /usr/bin/rsync -avz {} \
/home/foobar/Pictures/Incoming/date +%Y-%m-%d/ \;
umount /tmp/x

(yes, I know this code is dirty, I should have used mktemp, but you get the point…)
Don’t forget to chmod +x the shell script and reload the configuration with:

udevcontrol reload_rules

For more detailed information about writing udev rules, take a look at the official documentation, or another’s detailed information about doing the same thing.


Write a Comment


  1. Hi there,
    I was playing a little bit with “udev” and code based on yours script – I make backup of my pendrive every time it’s plugged in -, however I face strange situation:
    my script is terminated at random line – which means that few first lines are executed and the rest is not. After some time i realized that window which popups when you plug pendrive in interfere with my script – but how? I’ve read in udev docs that udev will wait for script to finish, does it open separate threats?
    I did nasty workaround by putting “sleep 10” at the beginning of my script – it lets window to open but it’s dirty. Can You explain why such situation occurs and how to solve it? :D I appreciate any help.

  2. This works great!
    I’ve added a quick e-mail notice to mine that tells me when the file transfer is done, and how much space is left on the external drive. This is extremely useful