Hey so MacBooks have this nasty habit of not mounting external disks when plugged in before… reference link
the solution is quite simple with terminal eject the disk and the manually unplug replug the drive.
I'd like to make a small AppleScript that can do the whole process of looking for the disk and if found eject it. This is what i got, but I'm stuck on recognising if the external disk is found by terminal…
tell application "Terminal"
do script "echo \"diskutil list\"" in window 1
if exists disk2 then
do script "echo \"diskutil info disk2\"" in window 1
do script "echo \"diskutil eject disk2\"" in window 1
do script "echo \"diskutil list\"" in window 1
end if
end tell
the error i get is The variable disk2 is not defined.
questions are:
1) if i print the diskutil list, how would i define variables for all the external disk terminal found?
2) see if it's mounted, if not try to mount, if fails eject?
Best Answer
You're actually writing a shell script, and the AppleScript context seems rather superfluous at the moment. If you're predominantly using shell commands, you may want to consider writing a shell script instead.
I've employed a little of both because they each have their usefulness in this situation: the shell commands are necessary to retrieve the disk information via
diskutil
, since AppleScript has no inbuilt means of getting that information by itself; but then rather than mess around withgrep
,awk
, orsed
to pattern match text from the raw output, we can invoke the-plist
option to return the output as XML-formatted property list data, which AppleScript can be very good at handling.1. Retrieving a list of local disks and volumes
Locally attached disks and volumes have a blockdevice inode in the folder
/dev
, so getting a list of disks is pretty easy with AppleScript:With my USB drive attached, I get this list of inodes:
2. Isolating the desired volumes
To filter the list so that we only run the appropriate utilities on the appropriate disks or volumes,
diskutil
now does its part. We can create a shell process from inside AppleScript rather than doing it via Terminal. The relevant shell command is this:To execute this from AppleScript, use the
do shell script
command:where
id
is the name of a disk retrieved from earlier and stored indiskinfo
. You can't pass in the entire list all at once, so we have to iterate through the list and run the command once for each item:With the property list data returned by
diskutil
, AppleScript can turn it into aproperty list
object. The property list data returned by invokingdiskutil info
is all contained within a single level, so there's no hierarchy to traverse. The great thing withproperty list
objects is that AppleScript can transform them into arecord
, which then becomes really easy to retrieve values:In a single line, AppleScript has read the property list data, and discarded any disk that is:
It also bins all the useless data we don't need, and returns only the name of the partition and its parent disk. These will only be ejectable disks (so not the recovery and boot disks, and not your computer's hard disk), and will be mountable volumes that are not currently mounted. For me, and my single USB drive, which I unmounted first, I got this record list back:
3. Mounting and ejecting each volume
The parsing of the data is now done, so now you can run
diskutil
operations on the appropriate disks. You have the choice of either mounting individual volumes, or mounting an entire disk (which will mount all of its volumes). The method is the same for each: iterate through our record list stored in the variableunmounted
and use either thedisk
or thevolume
from each item as an argument for the appropriate shell command:The AppleScript loop looks like this:
do shell script
returns on success the output tostdout
. After successfully mounting my disk, the messages pane in Script Editor contained:I haven't instigated a situation that forces my drive not to mount, but typically, upon failure of any shell command (that is, whenever a shell command returns a non-zero status),
do shell script
throws an error. This will be caught by thetry
block, which will redirect the script to execute another shell command responsible for ejecting the drive. This is also in its owntry
block in case it, too, returns a non-zero status, in which case the script will continue onto the next volume.Below is the final script with some additional modifications. The script will return the original unmounted record list with extra information appended to each disk item reporting the outcome of the attempt to mount and/or eject the volume. A complete failure will simply be reported with
false
. So my final script result looked like this:The final script