10

I've been looking into running a few cleanup commands when a user logs out, however the old logout hook feature, although still functioning, has been deprecated for some time now so may not be with us for much longer.

Unfortunately, although launchd provides a convenient alternative to login hooks, there is no such obvious replacement for logout hooks.

I've already experimented with creating a shell script that is launched on login, and simply sleeps until a kill signal is received, however this doesn't seem to work (the script never receives the signal during normal operation).

Otherwise I'm not sure what the best way to run a quick command on logout would be? I know there are some third party utilities that can do it, but is there a "correct" way to do this anymore?

7
+50

It seems that Apple isn't interested in a logout hook replacement, as they closed my issue inquiring about one.

However, one of the improvements in Yosemite is that launchd now properly sends signals down to shell scripts. What this means is that you can now do a log-out task like so:

Here's an example logout.sh:

#!/bin/sh
onLogout() {
    echo 'Logging out' >> ~/Logs/logout.sh.log
    exit
}

trap 'onLogout' SIGINT SIGHUP SIGTERM
while true; do
    sleep 86400 &
    wait $!
done

This will simply sleep (asynchronously, doing it synchronously without the ampersand doesn't seem to work) until it receives one of the trapped signals, at which point it will execute the onLogout function.

All you need to do is launch that script using a RunAtLoad launch agent or launch daemon and it will run at log-out or shutdown, though it's important to bear in mind that tasks only have a limited amount of time to complete before they are killed instead, so this shouldn't be used to run anything that takes a long time, or requires a network connection that could be delayed etc.

Of course this is of no use to anyone on Mavericks or earlier, but under Yosemite this now seems to work as expected; so I was actually doing it right in the first place, launchd just wasn't sending the signals properly :)

NOTE: For this to work the shell scripts seems to need to be executed directly by launched, i.e - it shouldn't invoked via sh. So if it were placed in ~/Library/Scripts/foo.sh your program arguments might look like:

<key>ProgramArguments</key>
<array>
    <string>~/Library/Scripts/foo.sh</string>
    <string>bar</string>
</array>
<key>EnableGlobbing</key>
<true/>
  • When I run this script, it returns line 8: syntax error near unexpected token ;' (with a grave before the semi-colon) – Jason Dec 30 '14 at 20:29
  • Whoops, you're right @Jason, I think I simplified it too much, I've tweaked it to more closely resemble a working example. – Haravikk Jan 28 '15 at 17:10
  • It triggers when I unload it using launchctl, but not when I log out or restart. Why? – Trellis Jan 30 '15 at 13:25
  • Is there a way to run it before the network goes down? – user824963 Dec 16 '18 at 9:51
2

You can use iHook to run login/logout hooks, which I've found to still work for non-interactive login and logout hooks written in Bash and Python on Yosemite.

http://rsug.itd.umich.edu/software/ihook/

  • Unfortunately this one still uses normal logout hooks under the hood. – 0942v8653 Oct 25 '14 at 11:47
0

If others who get here from search engines don't care about using a logout hook, run for example:

sudo defaults write com.apple.loginwindow LogoutHook '~/.logouthook';echo $'#!/usr/bin/env bash\n\nsay a'>~/.logouthook;chmod +x ~/.logouthook

Then ~/.logouthook is ran the next time you log out.

The value of the LogoutHook key has to be a path to an executable and not a shell command. The defaults command modifies /var/root/Library/Preferences/com.apple.loginwindow.plist.

  • Thanks for giving it as an alternative anyway, but my concern is that login and logout hooks have been deprecated for the last few versions of OS X; although I expect they still function in Yosemite (since it's mostly focused on the UI and Continuity changes) it seems like it could go at any time, like the old startup items being replaced by launchd, just a shame it doesn't have RunBeforeUnload or similar option. – Haravikk Oct 7 '14 at 10:05
0

I can't get the launchd logout item to work in 10.10.1, either, but the LogoutHook key in root's "com.apple.loginwindow.plist" works well. Are there any other examples for the launchd method?

Anyway, I wrote an AppleScript to kill system volume at logout so the startup chime won't be heard on next startup. What I haven't worked out are the details for managing multiple logout commands based on a single LogoutHook key, or whether it's possible to store multiple LogoutHook keys, so I'm still interested in the Launchd method, which could be managed with Lingon, or even Lingon 3, which has a much narrower scope than the original (presumably to exist in the App store).

set current_Vol to (do shell script "osascript -e \"output volume of (get volume settings)\"")
if button returned of (display dialog "Do you want to silence the startup chime, restore it, or cancel?" buttons {"Silence", "Restore", "Cancel"} default button 1) is "silence" then
    do shell script "mkdir -p  /usr/local/logouttask;echo '#!/bin/bash
# logout script
osascript -e \"set volume 0\"' > /usr/local/logouttask/logoutscript;sudo defaults write com.apple.loginwindow LogoutHook /usr/local/logouttask/logoutscript;chmod +x /usr/local/logouttask/logoutscript" with administrator privileges
else
    try
        do shell script "sudo defaults write com.apple.loginwindow LogoutHook '';rm /usr/local/logouttask/logoutscript" with administrator privileges
        display dialog "The startup chime will be heard if the volume setting is greater than 0 at shut down or restart." buttons {"OK"} default button 1
    on error the error_message number the error_number
        if error_number is 1 then
            display dialog "The script that sets system volume to zero at logout doesn't exist. The startup chime will be heard if the volume setting is greater than 0 at shut down or restart." buttons {"OK"} default button 1
        else
            display dialog "Error: " & the error_number & ". " & the error_message buttons {"OK"} default button 1
        end if
    end try
end if
  • How are you invoking the logout item? My example shell script for needs to be invoked directly (no use of sh) so it needs to be a file that is executable, I'll note that in my answer. – Haravikk Jan 28 '15 at 17:05
  • Thanks for updating. I'll try as soon as possible and let you know. – Trellis Jan 29 '15 at 15:46
  • I can only trigger the event contained in foo.sh by running "launchctl unload" on the plist that calls it in Terminal. Logging out doesn't trigger it. – Trellis Jan 29 '15 at 22:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .