Mounty - Menu-based temporary drive mounting

Using Bash, lsblk, dialog, and findmnt for fast USB drive mounts and dismounts
Created: 2019-05-25

So the other day, I found myself with a handful of USB flash drives, a pair of Kindle Paperwhites, and a little MP3 music player which can be mounted as a regular file system when it’s plugged in via USB.

The fstab entry I mentioned here works okay most of the time. But I was still having problems: sometimes there were permission issues, sometimes the drive would show up as /dev/sdc1 or (in the case of the Kindle and MP3 player) there’s no partitition, so they would need to be mounted from /dev/sdb or /dev/sdc.

So more often than not, I found myself resorting to painfully manual methods of locating the device, mounting it, navigating to the mount point, doing my transfer, and then unmounting. Ridiculous.

Along the way, I did discover a neat way to locate the Kindles: /dev/disk/by-label/Kindle which worked for both generation of Kindle Paperwhites. I wrote a couple Perl utilities to either auto-sync ebooks between my PC or open a file manager to manually manage them. But that only worked for the Kindles.

So I decided enough was enough: it was time to solve this USB mounting thing once and for all.

The result is a little Bash script I call "Mounty" which makes the process completely painless.

screenshot of graphical dialog-driven menu to select device

I use the dialog CLI application to display a graphical list of the detected block devices.

screenshot of vifm with the usb device and my local filesystem

The devices is mounted and the application of my choice is launched (vifm pictured here) with the mount point. When I quit the application, the drive is unmounted and Mounty quits.

I’m really happy with this and I just completed a bunch of really minor transfer, backup, and syncing tasks I’ve been putting off because the hassle just wasn’t worth it.

I don’t usually bother with source control for such tiny applications, so I don’t have a repo to link to for this. Instead, here’s the source of Mounty in its entirety:

#!/bin/bash

# mounty - menu-based temporary block device mounting

if [[ $EUID -ne 0 ]]
then
	echo "Must be run as root."
	exit 1
fi


# device list
devices=()

# read each block device description line from lsblk
# (using only the most helpful descriptors available from lsblk)
getlist="lsblk -l -p -n --output name,size,label,vendor,model"
while read d
do
	# let bash do word splitting to condense extra spaces:
	d=$(echo $d)

	# get the device path (first "word") followed by descriptors
	# using bash parameter expansion
	devices+=( "${d%% *}" "${d#* }" )
done < <($getlist) # process substitution

# display dialog menu with block device list where elements
# from array make choice,description pairs

selected=$(dialog \
	--stdout \
    --backtitle "Mounty" \
    --menu "Select a block device:" 0 0 10 \
	"${devices[@]}")

if [[ -z $selected ]]
then
	echo "No device selected."
	exit
fi

# take chosen selection and see if it's already mounted
#if findmnt $selected >/dev/null
if dir=$(findmnt --source $selected -n -o TARGET)
then
	echo "$selected already mounted at $dir"
else
	# mount it to a new temporary dir
	dir="/mnt/mounty"
	mkdir $dir
	echo "Mounting $selected at $dir..."
	mount $selected $dir || exit
fi

# now that it's mounted, call user-supplied arguments
$1 $dir $2 $3 $4 $5
#echo "running:" $1 $dir $2 $3 $4 $5

echo "Now unmounting $selected..."
umount $selected
echo "Done."

As you can see, there’s just a handful of commands here:

  • lsblk is used to list the block devices with helpful size, label, vendor, and model descriptors to make it easy to identify the device

  • I use bash parameter expansion to "parse" the simple output for the menu

  • dialog --menu displays the menu and returns the selected device path

  • findmnt returns an existing mount point for the device if it exists [1]

  • I call mount, then a command supplied as an argument to the script

  • After the command returns, I call umount to unmount the device immediately

Here’s my Bash alias for opening the mounted device and my local Music/ directory with vifm (the vi-like file manager).

alias mounty='sudo mounty vifm ~/Music'

Yeah, this runs as root and it just works. I’m done screwing around with alternative methods for now.

But, of course, I’m always open to something better. :-)