Creating a bootable Linux USB installer on MacOS

Estimated reading time: 3 minutes

Gerard Samuel Gerard Samuel's profile photo
Photo by Sara Kurfeß on Unsplash

Here is how I prepare a USB stick to be used to boot Linux installations.

  1. Download an ISO from ubuntu.com or federaproject.org

  2. In MacOS, convert the ISO to an image file.

Note
hdiutil convert -format UDRW -o $HOME/Downloads/file-name file-name.iso
  1. List all external storage devices plugged currently plugged in. Determine which is your USB device.
diskutil list external | grep -E '^/dev/disk[0-9]+\s'
  1. Erase the disk and format using the FAT32 format
diskutil eraseDisk FAT32 SETUP /dev/disk4
  1. Unmount the USB device
diskutil unmountDisk /dev/disk4
  1. Use “dd” to create the bootable USB from the image file created earlier
sudo dd if=file-name.dmg of=/dev/disk4 bs=1m
  1. Eject the USB device
diskutil eject /dev/disk4

With the general steps defined, let me put together a script that will automate the process

#!/usr/bin/env bash

set -Eeuo pipefail

# Create a temporary directory
TEMPDIR=$(mktemp -d)

# Define a cleanup function
cleanup_tmpdir() {
    printf "Removing temporary files..." &> /dev/null
    rm -rf "$TEMPDIR"
}

# sudo challenge function
function sudo-creds-challenge() {
    if [[ $EUID -ne 0 ]]; then
        sudo --reset-timestamp

        if ! sudo --prompt "Elevate your shell by entering your password here:" true
        then
            printf "Unable to validate your sudo credentials.  Exiting"
            exit 1
        fi
    fi
}

# Trap signals to execute the cleanup function
trap cleanup_tmpdir EXIT

# Test input for an ISO file
if [ -z "$1" ]; then
    printf "Please pass in a path to a local ISO file"
    exit 1
fi

# Test for the existence of plutil on MacOS
if [ ! command -v plutil &> /dev/null OR ! command jq &> /dev/null ]; then
    printf "Required commands plutil or jq is required on MacOS"
    exit 1
fi

# Get a list of attached USB storage devices
devices=($(diskutil list -plist external physical | plutil -convert json -r -o - - | jq -r '.AllDisksAndPartitions[].DeviceIdentifier'))

if [ "${#devices[@]}" -gt "0" ]; then
    PS3="Choose a USB storage device from the list above:"

    select device in "${devices[@]}"; do
        # printf "Selected device: $device"
        # printf "Selected number: $REPLY"
        [[ -n $device ]] && break || {
            printf "== Invalid Option ==\n\n"
        }
    done
else
    printf "\nA USB storage device has not been detected"
    exit 0
fi

USB_DEVICE="/dev/${device}"
ISO_FULL_PATH=$1
ISO_BASE_FILE=$(basename -- $ISO_FULL_PATH)

sudo-creds-challenge

# Erase the USB storage device
printf "\nErase USB storage device ${USB_DEVICE}? (Y/N) "
read CHOICE

case $CHOICE in
    [Yy])
        printf "\nErasing disk ${USB_DEVICE}\n"
        diskutil eraseDisk FAT32 SETUP $USB_DEVICE
        ;;
    *)
        printf "\nExiting script..\n"
        diskutil eject $USB_DEVICE
        exit 0
        ;;
esac

# Unmount the USB storage device
printf "\nUnmounting ${USB_DEVICE}\n"
diskutil unmountDisk $USB_DEVICE

# Convert the iso file to a disk image
DMG_FILE="${TEMPDIR}/$ISO_BASE_FILE%.*"
printf "\nConverting the ISO file to a DMG temp file in ${TEMPDIR}\n"
hdiutil convert -format UDRW -o $DMG_FILE $ISO_FULL_PATH

# Write the disk image to the USB storage device
printf "\nWriting disk image to the USB storage device\n"
sudo dd if="${DMG_FILE}.dmg" of=$USB_DEVICE bs=4m status=progress

if [ $? == 0 ]; then
    printf "\nProcess completed successfully. Ejecting the USB device.\n"
else
    printf "\nAn error occurred writing to the USB storage device.\n"
fi

diskutil eject $USB_DEVICE

For further instructions on how to use the script, please head over to my Gitlab repo.

Thanks