Skip to content

Instantly share code, notes, and snippets.

@chrischan514
Last active August 17, 2023 21:37
Show Gist options
  • Save chrischan514/1b5c1f59abee5356adb1e7cf34552ccf to your computer and use it in GitHub Desktop.
Save chrischan514/1b5c1f59abee5356adb1e7cf34552ccf to your computer and use it in GitHub Desktop.
One-key eject all external storage devices from macOS (works with external hard drives and USB devices, not tested with disc drives)
#!/usr/bin/python
import os,re, subprocess
diskUtilList = os.popen('diskutil list').read()
externalPhysicalRegEx = r".*\/dev\/(disk((?:\d+))) \(external\, physical\).*"
extDiskIntRegex = r".*\/dev\/disk(\d+) \(external\, physical\).*"
diskList = re.findall(extDiskIntRegex, diskUtilList)
for disk in diskList:
diskint = int(disk)
match = "disk"+str(disk)
print('Found '+ match)
#Check if there are any APFS Volumes
APFSVolCount = re.findall(r"Apple_APFS.*disk"+disk+r"s",diskUtilList)
#Do unmount APFS procedure if there are any APFS Containers
if len(APFSVolCount) == 0:
print('No APFS Containers on this drive, skipping ...')
else:
if len(APFSVolCount) == 1:
containerString = 'Container'
else:
containerString = 'Containers'
print('\nFound '+ str(len(APFSVolCount)) + ' APFS '+containerString)
#Unmount APFS volumes individually
for APFSVols in APFSVolCount:
diskassg = re.findall(r"Apple_APFS.*(disk\d+)(?!s)", APFSVols)
print('Processing '+ ', '.join(diskassg))
for motherVolume in diskassg:
print('\nUnmounting APFS Volumes on ' + motherVolume)
APFSvolumesList = re.findall(r"APFS Volume.*("+motherVolume+r"s\d+).*", diskUtilList)
APFSvolumesListPrint = ', '.join(APFSvolumesList)
print('APFS Volumes found: ' + APFSvolumesListPrint)
for APFSVolume in APFSvolumesList:
print("Unmounting " + APFSVolume + " ...")
unmountProcess = subprocess.Popen('diskutil unmountDisk force '+APFSVolume, shell=True, stdout=subprocess.PIPE)
unmountProcess.wait()
if unmountProcess.returncode == 0:
print('Unmounted successfully')
else:
print('Unexpected error occured')
#To unmount other volumes
volumesList = re.findall(r".*(disk"+disk+r"s\d+).*", diskUtilList)
volumesList = list(dict.fromkeys(volumesList))
for volume in volumesList:
print("\nUnmounting "+ volume + '...')
unmountProcess = subprocess.Popen('diskutil unmountDisk force '+volume, shell=True, stdout=subprocess.PIPE)
unmountProcess.wait()
if unmountProcess.returncode == 0:
print('Unmounted successfully')
else:
print('Unexpected error occured')
#Eject disk after unmounting, hard drives should shut itself down
print("\nEjecting " + match + " ...")
unmountDiskProcess = subprocess.Popen('diskutil unmountDisk force '+match, shell=True, stdout=subprocess.PIPE)
unmountDiskProcess.wait()
if unmountDiskProcess.returncode == 0:
print('Unmounted successfully')
else:
print('Unexpected error occured')
ejectDiskProcess = subprocess.Popen('diskutil eject '+match, shell=True, stdout=subprocess.PIPE)
ejectDiskProcess.wait()
if ejectDiskProcess.returncode == 0:
print('Ejected successfully')
else:
print('Unexpected error occured')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment