This is really just a do shell script
curiosity rather than a problem, but I’d welcome any thoughts.
I was looking for way to get user names and IDs from AppleScript and noticed that System Events is kind enough to give us user names, so starting there:
set userNames to {}
tell application "System Events"
repeat with aUser in users
set end of userNames to aUser's name & " "
end repeat
end tell
However, System Events isn’t so generous to provide the user id numbers that I want to go along with them. For that, it seems we need to go to the shell. So, adding the above to a do shell script
loop, we can get the required info* like this:
Script 1
set userNames to {}
set userIDs to {}
tell application "System Events"
repeat with aUser in users
set end of userNames to aUser's name & " "
end repeat
end tell
repeat with i from 1 to count of userNames
set aName to item i of userNames
set userID to do shell script "id -u " & aName
set end of userIDs to {aName, userID}
end repeat
userIDs
That gives the output I want, but it’s noticeably slow. Best time I could get out of it was about ~0.75-0.85 seconds**.
Now the fastest way to get the info I want directly in the shell is to do this:
dscl . list /Users UniqueID | egrep -v ^'_|daemon|nobody|root'
But surprisingly, wrapping that inside a ‘do shell script’ is even slower (~1.0) than the first script.
Script 2
do shell script "dscl . list /Users UniqueID | egrep -v ^'_|daemon|nobody|root'"
That surprised me because I though the first script’s slowness was probably down to the repeated do shell script
calls in the loop, but no. There’s only one call here and it’s still slow. Just to be clear, this can’t be put down to the shell command. Try it directly in the shell and you’ll see just how fast it is when run natively.
But what came as even more of a surprise was this one, which turns out to be the fastest of all (<0.4):
Script 3
do shell script "userNames=$(osascript -e 'set usrNms to {}' -e 'tell app \"System Events\"' -e 'repeat with aUser in users' -e 'set end of usrNms to name of aUser & \" \"' -e 'end repeat' -e 'end tell' -e 'set str to items of usrNms as text');for u in $userNames; do printf $u\" \" ; id -u $u; done"
This crazy construction splits the applescript up into single lines and calls each line with osascript, then uses the shell to parse the result and iterate over each username. It is, in effect, a shell version of the first script, but THEN wrapped inside of a do shell script
.
That such byzantine construction should turn out to be twice as fast as the first one and nearly three times faster than the second one is something I find completely baffling.
I don’t suppose anyone can offer any enlightenment on this curiosity?
Either way, the takeaway here for me is that it’s worth experimenting with your do shell script
's if speed is at all an issue.
* I should point out that Script 2 will also reveal any hidden users, whereas Script 1 and Script 3 will not.
** Caveat on the timings: these are based on SD’s timer; I didn’t try the scripts in SE. I’d expect them to be individually faster, but presumably relatively the same to each other.