Ubuntu – Executing a script when inserting a flash drive

scriptsudevusb

How can I write a script that fires on an event?

When I insert an USB flash drive, Ubuntu mounts it and automatically opens Nautilus.
When this happens with a specific flash drive, I'd like to open a second tab with a determinate folder.

I don't think it can be done with a Nautilus script, but how can I do it with a Linux script or a Nautilus extension?

Best Answer

If you run the script below in the background, it checks for mounted volumes. If one of your defined drives is mounted, it automatically opens the set folder in nautilus.

A minor problem was that nautilus does not support opening a directory in a new tab from command line, only in a new window. That means that the initial window, that appears if you insert a usb drive, has to be gracefully closed. The script uses wmctrl to do that, at the same moment that your chosen folder will open.

You might need to install it first:

sudo apt-get install wmctrl

The script

#!/usr/bin/env python3

import subprocess
import time

#--
drivename_folders = [("My Passport", "docs"), ("7827-2F8C", "sanel")]
#--

def get_mountedlist():
    return [item[item.find("/"):] for item in subprocess.check_output(
            ["/bin/bash", "-c", "lsblk"]).decode("utf-8").split("\n") if "/" in item]

done = []

while True:
    mounted = get_mountedlist()
    new_paths = [dev for dev in mounted if not dev in done]
    valid = sum([[(drive, drive+"/"+item[1], item[0]) for drive in new_paths \
                  if item[0] in drive] for item in drivename_folders], [])

    for item in valid:
        open_window = "nautilus  "+"'"+item[1]+"'"
        close_window = "wmctrl -c  "+"'"+item[2]+"'"
        subprocess.Popen(["/bin/bash", "-c", open_window])
        time.sleep(1)
        subprocess.Popen(["/bin/bash", "-c", close_window])

    done = mounted
    time.sleep(2)

How to use

  1. Copy the script into an empty file

  2. Set your drives and folders

    In the head section of the script, change the line:

    drivename_folders = [("My Passport", "docs"), ("7827-2F8C", "MyFolder")]
    

    where every tuple represents a drive(name), and the folder inside the drive that has to be opened. I left my "test" -names as an example.
    If you are not sure about the exact name of your drive, run lsblk to see the name (without the preceding path to the mountpoint)

  3. Save the script

    Save the script as open_folder.py and run it by the command:

    python3 /path/to/open_folder.py
    

If all works as you expected, add it to your Startup Applications

How it works

  • Every two seconds, the script runs the lsblk command to check for all mounted volumes.
  • If it finds one or more newly mounted volume name(s), it checks if the name is in the list of volumes that you set to be opened in a specific way (opening a sub directory)
  • The script opens the sub directory of the volume that you defined, and closes the (drive's root-) window that was automatically opened on connecting the drive.
  • To prevent repeatedly opening the folders, the volume then is added to the "done" list, until the volume is unmounted.

Other file managers

I tested it on pcmanfm (Lubuntu) and thunar (Xubuntu) and, as expected, in both cases, it workes fine.

If you want to use it on either Lubuntu or Xubuntu, change the line:

open_window = "nautilus  "+"'"+item[1]+"'"

to:

open_window = "thunar "+"'"+item[1]+"'"
(for Xubuntu)

or

open_window = "pcmanfm "+"'"+item[1]+"'"
(for Lubuntu, also disable in pcmanfm's preferences: Media > "Show available options for removable media")

Of course, make sure wmctrl is installed

Most likely, it will work on other file managers as well.


Generalized version of the script

The version of the script above is specifically for one situation. To be able to use the script in a broader range of purposes (to run any command when a specific drive gets connected, making backups of it for example) the version below could be useful.

In this case, in the head section of the script, the tuples represent:

 drivename_folders = [(<drivename_a>, <command_a>), (<drivename_b>, <command_b>)]

see the "test" setting in the script below.

The script

#!/usr/bin/env python3

import subprocess
import time

#--
drivename_command = [("My Passport", "gnome-terminal"), ("F806-0C50", "gedit")]
#--

def get_mountedlist():
    return [item[item.find("/"):] for item in subprocess.check_output(
            ["/bin/bash", "-c", "lsblk"]).decode("utf-8").split("\n") if "/" in item]

done = []

while True:
    mounted = get_mountedlist()
    newly_mounted = [dev for dev in mounted if not dev in done]
    valid = sum([[(drive, item[1]) for drive in newly_mounted \
                  if item[0] in drive] for item in drivename_command], [])
    for item in valid:
        subprocess.Popen(["/bin/bash", "-c", item[1]])
    done = mounted
    time.sleep(2)

How to use

  1. Copy the script into an empty file

  2. Set your drives and commands

  3. Save the script

    Save the script as drive_run.py and run it by the command:

    python3 /path/to/drive_run.py
    

If all works as you expected, add it to your Startup Applications

Related Question