It’s a question we get every now and again that simply doesn’t have an easy answer: “How do I add items to the Login Items from the Terminal?”
Well, that’s hard, and mainly because the defaults command is limited in that it cannot nest collections and the folks that made the plist for loginwindow decided on an array of dictionaries, thus tossing that command out the window as a solution.
$ defaults write foo test -array-add -dict Hide 1 Path /Applications/TextEdit.app
2007-04-09 20:44:42.659 defaults[17951] Cannot nest composite types (arrays and dictionaries); exiting
So I poked around at how applications do it when adding daemons and such and it turns out they do it by one of two methods. The first is the obvious one: they edit the loginwindow plist and add in the item. It’s just a dictionary with two keys and it’s only written when changes are made in the Accounts preference pane, so it’s no big deal to edit outside of that (unlike the Dock’s preferences).
Now the second one is kind of fun, and quite open to CLI scripting. You can talk to the System Events program via AppleScript and have it mangle the property list for you. You can even get a list of items and replace them if you so choose. Well, AppleScript can be accomplished in Terminal rather easily, so let’s take a look at a script that does what we want so we can make a reduction:
tellapplication “System Events” tomake new login item with properties {path: “/Applications/TextEdit.app”, hidden:false} atend
Voila! We have a new Login Item. (Go ahead and run this and then check the Login Items pane of the Accounts preferences.) So, now it needs to run in Terminal. Well, osascript will do this:
/usr/bin/osascript -e 'tell application "System Events" to make new login item with properties { path: "/Applications/TextEdit.app", hidden:false } at end'
That works great. The only caveat being that it’s a PITA to type. So, let’s make a simple shell command out of it:
#!/bin/bash
/usr/bin/osascript -e "tell application \"System Events\" to make new login item with properties { path: \"$1\", hidden:false } at end"
Because it’s expecting a POSIX path anyway, you don’t need to bother with a conversion to a file reference or alias or whatever. Just use a plain old Unixy string as the argument and it works. Also, be aware that the quotes had to change so that the shell would expand the $1 variable.
Now, presuming you saved it as addloginitem somewhere in your PATH, you can just run:
$ addloginitem /Applications/TextEdit.app
login item TextEdit
Ta da.
This does require a user to be logged in and will only change the preferences for that user. If you want something different then you’re hacking up plists.
Going From Here
You can play around with this in Script Editor a little, too. This should give you some other ideas of the fun to be had.
tell application "System Events"
make new login item with properties {path:"/Applications/TextEdit.app", hidden:false} at login item 2
end tell
tell application "System Events"
set theItem to every login item whose path contains "TextEdit"
delete theItem
end tell
Just to mention a couple of alternatives, 'defaults' actually can be used to add login items if you add the whole "dict" as the value, eg:
/usr/bin/defaults write loginwindow AutoLaunchedApplicationDictionary -array-add '{Hide=1;Path="/Applications/Safari.app";}'This won't work as a general method to add a "dict" to an "array" because it only adds values that are a "string" data type. Luckily, it works with the loginwindow.plist file because although the "Hide" property usually takes a boolean, a string works just fine. But even if it didn't, if you don't care about the hiding part, you could just add the "Path" and it should still work as a login item.
Also, although it isn't a part of a standard install "PlistBuddy" is a tool included with many Apple updates and you may find several copies in your "/Library/Receipts" folder. It offers the added flexibility of being able to change and delete various parts of individual login item entries. It can also be used to add new ones, but that's a little tedious - "defaults" is simpler.
PlistBuddy actually is part of a standard 10.4 install. Every Tiger machine should have a copy in /Library/Receipts/AdditionalEssentials.pkg/Contents/Resources/PlistBuddy . So you can feel free to write scripts that use it, knowing it’s there. Sometimes it’s a life-saver.
PlistBuddy actually is part of a standard 10.4 install. Every Tiger machine should have a copy in /Library/Receipts/AdditionalEssentials.pkg/Contents/Resources/PlistBuddy . So you can feel free to write scripts that use it, knowing it’s there. Sometimes it’s a life-saver.
As mentioned by biovizier you can do this. I used a slightly different method. For example, I needed to get a login script (long story: AD plug-in) to add growl:
/usr/bin/defaults write ~/Library/Preferences/loginwindow “AutoLaunchedApplicationDictionary” -array-add ‘Hide Path /Library/PreferencePanes/Growl.prefPane/Contents/Resources/GrowlHelperApp.app ‘
Not actually my idea. I saw it at macosxhints.com. Works a treat. I found the correct XML by creating it manually and then inspecting the plist file. It’s a binary plist but you can convert it with the plutil command.