Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!


Click here to return to the 'This script is flawed!' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
This script is flawed!
Authored by: vczilla on May 07, '12 03:48:54PM

I'm sorry to have to point this out but this script does not work.

The main problem is this:

It builds two list, one of all local mount points and the other of their corresponding device names. Or at least that's the theory but in practice the first list is built using 'df -l' which indeed list the free space of all local volumes whereas the other one is built with 'df -k' which simply lists the free space of *all* mounted volumes ( the parameter '-k' here tells df to use 1024k blocks, it is useless for our purpose ).

So the two lists are out of sync and the wrong disk ends up being unmounted.

Anyway for the tl;dr crowd here is a corrected version (I hope ! I would look stupid otherwise ;-) )

set my_devs to {}
set my_disks to {}

set startup_disk to (characters 1 thru -2 of (path to startup disk as text)) as text

repeat with p in paragraphs of (do shell script "df -l|tail -n +2")
	try
		set my_dev to (do shell script "echo " & p & "|awk '{print $1}'")
		set my_disk to (do shell script "echo " & p & "|awk -F / '{print $5}'")
		if (my_disk is not "") then
			set the end of my_disks to my_disk
			set the end of my_devs to my_dev
		end if
	end try
end repeat

set your_selected_device_ids to choose from list my_disks with prompt "Please choose one or more volumes to be unmounted." with multiple selections allowed

repeat with my_res in your_selected_device_ids
	set my_id to get_index_from_element(my_disks, my_res as text)
	set my_dev to item my_id of my_devs
	try
		do shell script "diskutil unmount " & my_dev
	end try
end repeat

on get_index_from_element(my_list, my_item)
	local item_to_test
	
	repeat with i from 1 to (count my_list)
		set item_to_test to item i of my_list
		if item_to_test = my_item then
			return i
		end if
	end repeat
	error "Item:" & my_item & " not found " from my_list
end get_index_from_element

Please note that this was merely an exercise in correction and this script is by no way the shortest or most elegant way of doing this. For instance as someone suggested we could unmount our selected devices by name using only one list.

If I have time I'll repost a comment with this script redone in perl and parsing the output of diskutil because 'df -l' mistakenly lists a USB volume as a local volume on my machine.

Edited on May 07, '12 11:43:40PM by vczilla


[ Reply to This | # ]
This script is flawed!
Authored by: llee on May 08, '12 10:24:23PM

But "df -k | awk -F/ '/disk*/ {print $3}'" doesn't list all mounted volumes, not in Lion, anyway. The "df" command apparently always lists results in the same order, so, if the corresponding lists both reflect members which are appropriately filtered, as appears to be the case for the original script, then the items are matched correctly. Also, how could a USB volume be considered anything other than a local volume? If you don't consider it local, how do you define it?

Edited on May 08, '12 10:33:44PM by llee



[ Reply to This | # ]
This script is flawed!
Authored by: vczilla on May 09, '12 12:10:12PM

Hi llee,

This is 'df -k' on my machine:

%df -k
Filesystem                  1024-blocks      Used Available Capacity  Mounted on
/dev/disk0s2                   79203656  37059420  41888236    47%    /
devfs                               213       213         0   100%    /dev
map -hosts                            0         0         0   100%    /net
map auto_home                         0         0         0   100%    /home
/dev/disk2s2                  365784156 332133392  33650764    91%    /Volumes/LionHD
/dev/disk1s1                   66559996  65618364    941632    99%    /Volumes/NtfsData
/dev/disk1s2                   36141052  35825216    315836   100%    /Volumes/Stuff
/dev/disk1s3                   53588152  48312924   5275228    91%    /Volumes/Spare
/dev/disk3s1                  256702603 251655315   5047288    99%    /Volumes/LX 640GB
/dev/disk3s2                  306239060 303196948   3042112   100%    /Volumes/MacExt
//mono@mono-ubuntu/DATA        90905756  88700324   2205432    98%    /Volumes/DATA
/dev/disk3s3                   35929372  34222204   1707168    96%    /Volumes/SmallSave
//mono@mono-ubuntu/SHARED      30925528  28483832   2441696    93%    /Volumes/SHARED
//mono@mono-ubuntu/WINSHARE   122047484 119958196   2089288    99%    /Volumes/WINSHARE
/dev/disk4s2                     113970    113970         0   100%    /private/tmp/UpdateEngine-mount.gg0KUq6yFM
/dev/disk2s3                  365949948 333945836  32004112    92%    /Volumes/Windows 8

The three volumes with names in all caps are SMB shares mounted by the finder.

Now 'df -hlg':

%df -hlg
Filesystem   1G-blocks Used Available Capacity  Mounted on
/dev/disk0s2        75   35        39    47%    /
/dev/disk2s2       348  316        32    91%    /Volumes/LionHD
/dev/disk1s3        51   46         5    91%    /Volumes/Spare
/dev/disk3s2       292  289         2   100%    /Volumes/MacExt
/dev/disk3s3        34   32         1    96%    /Volumes/SmallSave
/dev/disk4s2         0    0         0   100%    /private/tmp/UpdateEngine-mount.gg0KUq6yFM
And for good measure the output of 'mount':
%mount
/dev/disk0s2 on / (hfs, local, journaled)
devfs on /dev (devfs, local, nobrowse)
map -hosts on /net (autofs, nosuid, automounted, nobrowse)
map auto_home on /home (autofs, automounted, nobrowse)
/dev/disk2s2 on /Volumes/LionHD (hfs, local, journaled)
/dev/disk1s1 on /Volumes/NtfsData (ntfs-3g, local, synchronous)
/dev/disk1s2 on /Volumes/Stuff (ntfs-3g, local, synchronous)
/dev/disk1s3 on /Volumes/Spare (hfs, local, journaled)
/dev/disk3s1 on /Volumes/LX 640GB (ntfs-3g	, local, nodev, nosuid, synchronous)
/dev/disk3s2 on /Volumes/MacExt (hfs, local, nodev, nosuid, journaled, noowners)
//mono@mono-ubuntu/DATA on /Volumes/DATA (smbfs, nodev, nosuid, mounted by mono)
/dev/disk3s3 on /Volumes/SmallSave (hfs, local, nodev, nosuid, journaled, noowners)
//mono@mono-ubuntu/SHARED on /Volumes/SHARED (smbfs, nodev, nosuid, mounted by mono)
//mono@mono-ubuntu/WINSHARE on /Volumes/WINSHARE (smbfs, nodev, nosuid, mounted by mono)
/dev/disk4s2 on /private/tmp/UpdateEngine-mount.gg0KUq6yFM (hfs, local, nodev, nosuid, read-only, noowners, nobrowse)
/dev/disk2s3 on /Volumes/Windows 8 (ntfs-3g, local, synchronous)

Hence the problem I mentioned.

You have two lists of a different size so when the script is using the position of an item in the first list to index an item in the second list the wrong item is picked up from the list and the wrong drive ends up being unmounted.

Just try both ( your version and mine ) and you'll see.

As for the second point you mentioned, you are totally right, USB drives are local disks and 'df -l' is of course completely justified in listing them. I was somehow thinking about 'internal drives' when I wrote my post.



[ Reply to This | # ]
This script is flawed!
Authored by: llee on May 09, '12 01:08:59PM

The only way that I could replicate your results, I guess, would be to try to create mountable volumes with all those disk names. But I did considerable testing on the script I submitted with quite a few different volumes mounted. The list you include first (yours is generated by "df -k") when generated by my script does not include all the volumes that yours includes because it isn't "df -k", it's "df -k | awk -F/ '/disk*/ {print $3}'", and it returns a listing for only the items appearing in your second list. My observation is that because the order of the listed items doesn't change between the filtering of the constructs based on "df -k" and "df -hlg", the script that filters out ineligible members still draws the correct association of items in the two lists. Can you store the output of the two initial commands from my script ("df -k | awk -F/ '/disk*/ {print $3}'", and "df -hlg | awk -F/ '/disk*/ {print $5}'") on your system so they can be compared line for line with the output you already included for "df -hlg"?

I know you already developed your own version which I find also appears to work for me, but it occurred to me that a refinement of the grep construct might provide both lists from "df -hlg" instead of one from "df -hlg" and the other from "df -k", so making that assumption, please see if the following change allows my script work for you.

In the original script, change

"df -k | awk -F/ '/disk*/ {print $3}'"

to

"df -hlg | grep -o 'disk[0-9][a-z][0-9]*'"

Based on that, I may be able to work out a version which doesn't involve creating the hash table (matching items of two lists).

Edited on May 09, '12 01:30:41PM by llee



[ Reply to This | # ]
This script is flawed!
Authored by: llee on May 09, '12 08:22:33PM

Hmm, well, could it be as short and sweet as this?

-----
set alldisks to paragraphs of (do shell script "df -hlg | awk -F/ '/disk*/ {print $5}'")
set nonbootnumber to (count of alldisks)
try
set alldisks to items 2 thru nonbootnumber of alldisks
activate
set your_selected_device_id to choose from list alldisks with prompt "Please choose one or more volumes to be unmounted." with multiple selections allowed
repeat with the_Item in your_selected_device_id
set the_ID to (do shell script "df -hlg | grep -m 1" & space & quoted form of the_Item & space & "| grep -o 'disk[0-9][a-z][0-9]*'")
try
do shell script "diskutil unmount /dev/" & the_ID
on error the error_message number the error_number
display dialog "Error: " & the error_number & ". " & the error_message buttons {"OK"} default button 1
end try
end repeat
on error the error_message number the error_number
if the error_number is -128 or the error_number is -1708 then
else
display dialog "There are no unmountable volumes." buttons {"OK"} default button 1
end if
end try
-----

Edited on May 09, '12 08:55:12PM by llee



[ Reply to This | # ]
I like it (shorter and simpler)
Authored by: vczilla on May 10, '12 09:32:23AM

I tried your shorter version and indeed it works here too. I think the key to this story was to have just one list, the one generated by 'df -l'.

Since you asked me (and I know that doesn't really matter anymore),
here is the output of 'df -k | awk -F/ '/disk*/ {print $3}' on my machine:

% df -hlg | awk -F/ '/disk*/ {print $5}'

LionHD
Spare
MacExt
SmallSave

and 'df -k | awk -F/ '/disk*/ {print $3}':

 df -k | awk -F/ '/disk*/ {print $3}'
disk0s2                   79203656  51490116  27457540    66%    
disk2s2                  365784156 332114676  33669480    91%    
disk1s1                   66559996  65618364    941632    99%    
disk1s2                   36141052  35825216    315836   100%    
disk1s3                   53588152  48312940   5275212    91%    
disk3s1                  256702603 251655316   5047286    99%    
disk3s2                  306239060 303196908   3042152   100%    
disk3s3                   35929372  34222232   1707140    96%   

That's why it didn't work here.

As a side note, there's a slight typo in the awk script regex, which should be /disk.*/ and not /disk*/ (luckily it doesn't change anything for the intended purpose).

I'm glad you didn't take it the wrong way and that you came up with a really short solution, and I hope I didn't came off as being too pedantic. ;-)



[ Reply to This | # ]