Pragmatism in the real world

Prevent an external drive from auto mounting on macOS

I have an external drive attached to the USB hub on my Thunderbolt Display that I use to clone my laptop’s internal drive every night using the schedule feature of SuperDuper!. At the appointed time, SuperDuper! will mount the external drive, clone the internal drive and then unmount the external drive again which is very convenient.

However, whenever I plug in my laptop, the drive automatically mounts. This doesn’t particularly worry me, but when I unplug my laptop from the display, I either have to unmount the drive first or I get an error. Today, after mumble mumble years of this, I finally decided to solve this by stopping this drive auto mounting.

To prevent a drive auto mounting on macOS, you add a line to /etc/fstab like this:

UUID={UUID} none {TYPE} rw,noauto

To obtain the UUID and TYPE, you can use diskutil info {device identifier} and look up the Volume UUID and Type (Bundle) values. You can look up the {disk identifier} using diskutil list.

For a clone of macOS that’s Catalina or more recent, there are two volumes that make up the one logical volume: the main read-only volume and also the “- Data” volume which contains everything that’s read write. For my external drive, these two volumes are called “Swiftsure Clone” and “Swiftsure Clone – Data”. Using diskutil list, I can see that “Swiftsure Clone” is disk4s1 and “Swiftsure Clone – Data” is disk4s5, so I need both UUIDs and types from diskutil info to craft the /etc/fstab entries.

This is far too much to remember for next time I replace this drive!

So I wrote a script, no_automount, that does it for me. To use it , I simply type: ~/bin/no_mount {name of drive} and it enters the two entries:

$ ./no_automount Swiftsure\ Clone
Added FAE11096-532A-38E5-BB91-AC4431036D09 (Swiftsure Clone - Data) to /etc/fstab
Added FB2A6631-8D19-4F5C-99C8-F16C83C14531 (Swiftsure Clone) to /etc/fstab

We can then prove that it got it right by looking at the file:

$ cat /etc/fstab
UUID=99519900-B474-456A-BA4C-B9086AF1C7F9 none apfs rw,noauto # Swiftsure Clone - Data
UUID=97505363-6A2F-46B5-9347-8A9B625F47C4 none apfs rw,noauto # Swiftsure Clone

and now my external drive no longer mounts when I plug it in!

The Script

As with all good automation projects, writing the script was much more work than doing it manually once!

no_automount:

#!/usr/bin/env bash

# Usage: ./no_automount My\ Disk

NAME=$1
if [ -z "$NAME" ] ; then
    echo "Usage: no_automount {Disk Name}"
    exit 1
fi

FSTAB=/etc/fstab

# Add an volume as not auto-mounted to the /etc/fstab file
# by it's identifier. Also pass in the volume name to add a
# comment on that line so that we can identify it later. 
function add_identifier {
    ID=$1
    VOLUME_NAME=$2
    if [ -z "$VOLUME_NAME" ] ; then
        echo "add_identifier() takes two parameters: ID and VOLUME_NAME"
        exit 2
    fi
    
    # get UUID and TYPE from `diskutil info $ID`
    UUID=`diskutil info "$ID" | grep "Volume UUID" | awk '{print $NF}'`
    TYPE=`diskutil info "$ID" | grep "Type (Bundle)" | awk '{print $NF}'`

    # Remove this UUID from fstab file
    sudo sed -i '' "/$UUID/d" $FSTAB

    # Add this UUID to fstab file
    echo "UUID=$UUID none $TYPE rw,noauto # $VOLUME_NAME" | sudo tee -a $FSTAB > /dev/null
    echo "Added $UUID ($VOLUME_NAME) to $FSTAB"
}

# Add all volumes that start with $NAME to the /etc/fstab such
# that they do not automout. 

# Get list of identifiers and volume names from `diskutil info`
LIST=`diskutil list | grep "$NAME"`

# Iterate over $LIST
echo "$LIST" | while read LINE
do 
    # Example of $LINE:
    #    1: APFS Volume Swiftsure Clone - Data 592.1 GB disk4s1

    # Extract disk identifier which is the last field on the line
    ID=`echo $LINE | awk '{print $NF}'`

    # Extract volume name in the middle of $LINE by: 
    #    1. remove all characters before $NAME using regex capture assign to $PARTIAL
    [[ ${LINE} =~ ($NAME.*) ]] && PARTIAL=${BASH_REMATCH[1]}
    #    2. Cut out the last 3 fields (size, units & ID) from $PARTIAL
    #       by reversing, cutting and un-reversing
    VOLUME_NAME=`echo $PARTIAL | rev | cut -d' ' -f 4- | rev`

    add_identifier $ID "$VOLUME_NAME"
done

# All done!
exit 0

I’ve comprehensively commented it in the hope that I’ll be able to remember how it works next time I need to look at it.

The most tricky bit was extracting the volume name from the middle of the line in the output of diskutil list to use a comment in /etc/fstab. In the end, I used regex to capture from the provided volume name to the end of the line and then a reverse cut to take off the last three fields. This feels a little inelegant, but it works!

If you need to prevent an external drive from automatically mounting when you plug it in, maybe this will help you too.

5 thoughts on “Prevent an external drive from auto mounting on macOS

  1. Hi,

    I wonder whether you use encryption on your Volumes?
    Just tried for an hour to prevent an encrypted APFS Volume from mounting – no luck so far, seems to just work with non encrypted apfs.
    Any suggestions appreciated!

  2. I have an encrypted external disk (FireVault) connected to one of the USB-C ports of a LG 5K display that I'm using for backups.
    Made the changes you suggested to /ect/fstab and it works like a charm with my encrypted disk (FileVault).
    OS: BigSur 11.3
    Thank you for this post :)

  3. This works a treat on the latest Mac update as well. I just touched /etc/fstab to create that file, and ran your script with the "Macintosh HD" name, rebooted and … gone.
    Thanks.

  4. This is very helpful and exactly what I was looking for. Thanks! I have made one small tweak. I found that my output from `diskutil list` contains non-ASCII characters, so I added a `tr` command to the pipeline when pulling the LIST to strip out the non-ASCII crud. Like so:

    LIST=`diskutil list | grep "$NAME" | tr -cd '\11\12\15\40-\176'`

Comments are closed.