This is a feature that’s now available on virtually all computers - the system automatically searches for devices in the background and mounts them. This feature might not be very useful in headless Linux systems, as USB drives need to be manually mounted each time. So I decided to write a script to automate USB mounting.
The goal is: when inserting a USB drive, the system automatically mounts it at /path-to-mount/label, where label is the USB drive’s name (note: avoid inserting two SD cards with the same label).
Auto-mounting
-
Check the SD card mount path on the mini PC:
lsblkOutput:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 476.9G 0 disk ├─sda1 8:1 0 512M 0 part /boot/efi ├─sda2 8:2 0 475.5G 0 part / └─sda3 8:3 0 976M 0 part [SWAP] sdb 8:16 1 58.9G 0 disk └─sdb1 8:17 1 58.9G 0 part sdc 8:32 1 0B 0 diskYou can see
sdb1is the SD card, but it’s not currently mounted. -
sdb1is a file located at/dev/sdb1. Find the UUID of this SD card:sudo blkid /dev/sdb1 /dev/sdb1: LABEL="Nikon-1" UUID="4A21-0000" BLOCK_SIZE="512" TYPE="exfat" PTTYPE="dos"LABELis the name you gave to the USB drive, which is what appears on the computer after inserting it. -
Create script
/usr/local/bin/auto-mount-usb.sh:#!/usr/bin/env bash logfile="/var/log/udev-usb-label.log" mount_base="/base-path-to-mount" exec >> "$logfile" 2>&1 logger "Auto-mount script triggered: $@" LABEL="$1" [[ -z "$LABEL" ]] && { logger "No LABEL provided" exit 1 } DEVICE=$(readlink -f "/dev/disk/by-label/$LABEL") if [[ ! -b "$DEVICE" ]]; then logger "Device for label $LABEL not found" exit 1 fi MOUNTPOINT="$mount_base/$LABEL" mkdir -p "$MOUNTPOINT" logger "Mounting $DEVICE to $MOUNTPOINT" if /usr/bin/mount -t auto -o uid=1000,gid=1000,umask=0022,iocharset=utf8 "$DEVICE" "$MOUNTPOINT"; then logger "Mounted $LABEL to $MOUNTPOINT successfully" else logger "Failed to mount $LABEL" exit 1 fi- Log files are stored in
/tmpand will be automatically cleaned after reboot. - Modify the mount point
mount_base="/base-path-to-mount". If you place everything in/home/username/, a new folder will be created with the USB drive’s label as the folder name each time. Be careful not to insert two SD cards with the same label.
- Log files are stored in
-
Refresh script permissions:
sudo chmod +x ./auto-mount-usb.sh -
Create systemd service
/etc/systemd/system/[email protected]:[Unit] Description=Auto Mount USB LABEL=%i After=local-fs.target [Service] Type=oneshot ExecStart=/usr/local/bin/auto-mount-usb.sh %i -
Create rules file
/etc/udev/rules.d/99-auto-usb-mount.rules:ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_LABEL}!="", ENV{SYSTEMD_WANTS}+="auto-mount-usb@%E{ID_FS_LABEL}.service" -
Reload:
sudo udevadm control --reload-rules sudo udevadm trigger sudo systemctl daemon-reload
Now when you insert a USB drive into Linux, a new folder will be automatically created at the specified location, and you can access your USB drive files.
Unmounting USB Drives
Always unmount the USB drive before ejecting it to avoid file corruption:
sudo umount /path_to_disk
If nothing is returned, you can safely eject the USB drive. If the mount point is in use, you can check which process is using it (note: if your terminal is within the USB path, unmounting will also fail):
sudo lsof +D /path_to_disk
After unmounting, the local folder won’t be deleted - it becomes a regular folder that you can manually delete if needed.
Raw Files
The main reason for mounting USB drives is to work with File Browser for file sharing. For example, I connect my camera to the mini PC, and friends can access and download photos from the camera’s SD card. My camera is a Nikon Zfc, which can save one RAW file (.NEF) for editing and one .jpg for preview. However, File Browser cannot preview RAW files online. So we can add a step to the /usr/local/bin/auto-mount-usb.sh script to automatically organize RAW files into a subfolder when an SD card labeled nikon-x is inserted. Then in File Browser, you can organize .jpg and .NEF files separately.
# -------- Nikon file classification logic --------
if [[ "$LABEL" == nikon-* ]]; then
logger "Detected Nikon device. Scanning for image files..."
TARGET_DIR="$MOUNTPOINT/DCIM/102NZ_FC"
RAW_DIR="$TARGET_DIR/RAW"
JPG_DIR="$TARGET_DIR/JPG"
if [[ -d "$TARGET_DIR" ]]; then
mkdir -p "$RAW_DIR" "$JPG_DIR"
# Move RAW files (.NEF)
find "$TARGET_DIR" -maxdepth 1 -type f -iname "*.nef" -exec mv {} "$RAW_DIR" \;
# Move JPG files
find "$TARGET_DIR" -maxdepth 1 -type f -iname "*.jpg" -exec mv {} "$JPG_DIR" \;
logger "Finished organizing files into RAW and JPG folders"
else
logger "Target directory $TARGET_DIR not found. Skipping file classification."
fi
fi
LRF Files
Similarly, DJI produces both .LRF and .MP4 files when recording videos. We can add a command to automatically distinguish between them:
# -------- DJI file classification logic --------
if [[ "$LABEL" =~ ^dji-[0-9]+$ ]]; then
logger "Detected DJI device. Scanning for video and LRF files..."
TARGET_DIR="$MOUNTPOINT/DCIM/DJI_001"
LRF_DIR="$TARGET_DIR/LRF"
MP4_DIR="$TARGET_DIR/MP4"
if [[ -d "$TARGET_DIR" ]]; then
mkdir -p "$LRF_DIR" "$MP4_DIR"
# Move .LRF files
find "$TARGET_DIR" -maxdepth 1 -type f -iname "*.lrf" -exec mv {} "$LRF_DIR" \;
# Move .MP4 files
find "$TARGET_DIR" -maxdepth 1 -type f -iname "*.mp4" -exec mv {} "$MP4_DIR" \;
logger "Finished organizing DJI files into LRF and MP4 folders"
else
logger "Target directory $TARGET_DIR not found. Skipping file classification."
fi
fi
Important Notes
- When using with File Browser Docker container, mount the USB first, then run the Docker container. Otherwise, files may not be found. If the container is already running, you can do
downthenupto restart. - The script immediately classifies files after USB insertion. It’s recommended to backup first before connecting to the mini PC to avoid file loss.
- If some files are classified and some are not, the program will only classify unclassified files. Repeated USB insertion/removal won’t cause issues.
- Files with the same name might cause data loss, but Nikon assigns IDs based on shutter count, so this isn’t a major concern.
udevil
Alternatively, instead of writing your own script, you can use udevil:
-
Install:
sudo apt update sudo apt install udevil -
Modify the configuration file
/etc/udevil/udevil.conf:allowed_media_dirs = /media/$USER, /run/media/$USERYou can set the default path here. Higher priority is given to entries listed first.
-
Create service file:
sudo nano /etc/systemd/system/devmon.service[Unit] Description=Devmon Auto-mount Service After=network.target [Service] Type=simple User=<your_username> Group=<your_username> ExecStart=/usr/bin/devmon Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target -
Reload configuration:
sudo systemctl daemon-reload sudo systemctl restart devmon