Vous êtes en fait en train d'écrire un shell script, et le contexte AppleScript semble plutôt superflu pour le moment. Si vous utilisez principalement des commandes shell, vous pouvez envisager d'écrire plutôt un script shell.
J'ai utilisé un peu des deux car ils ont chacun leur utilité dans cette situation : les commandes shell sont nécessaires pour récupérer les informations du disque via diskutil
puisque AppleScript ne dispose d'aucun moyen intégré pour obtenir cette information par lui-même. grep
, awk
ou sed
pour effectuer un filtrage de texte à partir de la sortie brute, nous pouvons invoquer la fonction -plist
pour renvoyer la sortie sous forme de données de liste de propriétés au format XML, qu'AppleScript sait très bien gérer.
1. Récupération d'une liste de disques et de volumes locaux
Les disques et volumes attachés localement ont un inode blockdevice dans le dossier /dev
Il est donc assez facile d'obtenir une liste de disques avec AppleScript :
use application "System Events"
property devices : a reference to files in folder "/dev"
property disknodes : a reference to (devices whose name begins with "disk")
set diskinfo to name of disknodes
Avec ma clé USB attachée, j'obtiens cette liste d'inodes :
--> {"disk0", "disk0s1", "disk0s2", "disk1", "disk1s1",
"disk1s2", "disk1s3", "disk1s4", "disk2", "disk2s1"}
2. Isoler les volumes souhaités
Pour filtrer la liste afin de n'exécuter que les utilitaires appropriés sur les disques ou volumes appropriés, diskutil
fait maintenant sa part. Nous pouvons créer un processus shell depuis l'intérieur d'AppleScript plutôt que de le faire via Terminal . La commande shell correspondante est la suivante :
diskutil info -plist <disk|volume>
Pour l'exécuter à partir d'AppleScript, utilisez la fonction do shell script
commandement :
do shell script "diskutil info -plist" & id
où id
est le nom d'un disque récupéré plus tôt et stocké dans le fichier diskinfo
. Il n'est pas possible de transmettre la liste entière en une seule fois, nous devons donc itérer dans la liste et exécuter la commande une fois pour chaque élément :
use scripting additions
delete every property list item
repeat with id in diskinfo
set shellcmd to "diskutil info -plist " & id
set plist to do shell script shellcmd
Avec les données de la liste de propriétés retournées par diskutil
AppleScript peut le transformer en un property list
objet. Les données de la liste de propriétés retournées en invoquant diskutil info
est contenu dans un seul niveau, il n'y a donc pas de hiérarchie à traverser. Ce qui est génial avec property list
est qu'AppleScript peut les transformer en un record
qui devient alors très facile de récupérer les valeurs :
make property list item with properties {name:id, text:plist}
tell the value of property list item id as record to if ¬
(its |Ejectable|) and (not its WholeDisk) and ¬
(its MountPoint = "") then set the contents of id ¬
to its {disk:ParentWholeDisk, volume:DeviceIdentifier}
end repeat
En une seule ligne, AppleScript a lu les données de la liste des propriétés, et écarté tout disque qui l'est :
- Non éjectable ;
- Est un disque "entier" (c'est-à-dire pas un volume montable) ;
- A un point de montage identifiable sur le système.
Il élimine également toutes les données inutiles dont nous n'avons pas besoin, et ne renvoie que le nom de la partition et de son disque parent. Ceux-ci ne seront éjectable (donc pas les disques de récupération et de démarrage, et pas le disque dur de votre ordinateur), et seront des volumes montables qui ne sont pas actuellement montés. Pour moi, et mon unique disque USB, que j'ai démonté en premier, j'ai récupéré cette liste d'enregistrements :
set unmounted to records of diskinfo
--> {{disk:"disk2", volume:"disk2s1"}}
3. Montage et éjection de chaque volume
L'analyse des données est maintenant terminée, donc vous pouvez maintenant exécuter diskutil
sur les disques appropriés. Vous avez le choix entre monter des volumes individuels ou monter un disque entier (qui montera tous ses volumes). La méthode est la même dans les deux cas : itérer à travers notre liste d'enregistrements stockée dans la variable unmounted
et utiliser soit le disk
ou le volume
de chaque élément comme argument pour la commande shell appropriée :
diskutil mount <volume>
diskutil mountDisk <disk>
diskutil eject <disk>
La boucle AppleScript ressemble à ceci :
repeat with diskitem in unmounted
set shellcmd to "diskutil mount " & diskitem's volume
try
do shell script shellcmd
on error
set shellcmd to "diskutil eject " & diskitem's disk
try
do shell script shellcmd
end try
end try
end repeat
do shell script
renvoie en cas de succès la sortie vers stdout
. Après avoir monté mon disque avec succès, le panneau des messages dans scriptÉditeur contenu :
"Volume USB on disk2s1 mounted"
Je n'ai pas encore créé de situation qui force mon disque à ne pas être monté, mais généralement, en cas d'échec d'une commande shell (c'est-à-dire lorsqu'une commande shell renvoie un état non nul), do shell script
lance une erreur. Cette erreur sera détectée par la fonction try
qui redirigera le script pour exécuter une autre commande shell responsable de l'éjection du lecteur. Ceci est également dans son propre try
au cas où il retournerait lui aussi un état non nul, auquel cas le script continuera sur le volume suivant.
Voici le script final avec quelques modifications supplémentaires. Le script retournera la liste originale des enregistrements non montés avec des informations supplémentaires ajoutées à chaque élément du disque rapportant le résultat de la tentative de montage et/ou d'éjection du volume. Un échec complet sera simplement signalé par false
. Donc mon résultat final script ressemblait à ceci :
--> {{disk:"disk2", volume:"disk2s1", result:"Volume USB on disk2s1 mounted"}}
Le script final
use application "System Events"
property devices : a reference to files in folder "/dev"
property disknodes : a reference to (devices whose name begins with "disk")
set diskinfo to name of disknodes
use scripting additions
delete every property list item
repeat with id in diskinfo
set shellcmd to "diskutil info -plist " & id
set plist to do shell script shellcmd
make property list item with properties {name:id, text:plist}
tell the value of property list item id as record ¬
to if (its |Ejectable|) ¬
and (not its WholeDisk) ¬
and (its MountPoint = "") then set ¬
id's contents to {disk:its ParentWholeDisk ¬
, volume:its DeviceIdentifier ¬
, result:missing value}
end repeat
set unmounted to records of diskinfo
repeat with diskitem in unmounted
set shellcmd to "diskutil mount " & diskitem's volume
try
do shell script shellcmd
set diskitem's result to the result
on error
set shellcmd to "diskutil eject " & diskitem's disk
try
do shell script shellcmd
set diskitem's result to the result
on error E
set disk item's result to E
end try
end try
end repeat
return unmounted