I have mentioned creating a self destructing script or launchd item a few times in articles on this site. But it was recently pointed out that I never actually showed how to go about doing so. Until recently I would actually use an out-of-band script to remove a script, a launchd agent or a launchd daemon. However, this would invariably leave elements somewhere on a file system of the script. For example, within a script I would echo out another script, fire off that script and then use it to delete (rm) the original script. When I planned out a deployment or a series of scripts I would always have one deploy the next, which would remove the first (I like being granular with my scripts rather than monolithic;). On top of leaving trace elements this was terribly inefficient.
Then I discovered that I could just put a line at the end of a script and it would erase itself when it was done running. So if I have a bind script with a password in the script and I want it to be removed when it is complete, I can just put the following line at the very end:
srm “$0”
The same logic can be applied to launchd items. Let’s say I kick off a script called myscript using a launchd item called com.krypted.myscript with the following contents:
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0″>
<dict>
<key>Disabled</key>
<false/>
<key>Label</key>
<string>com.krypted.myscript</string>
<key>ProgramArguments</key>
<array>
<string>sudo</string>
<string>./Scripts/selfdestruct.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Now at the end of this script (assuming a payload above these lines with a bunch of stuff you actually want to accomplish) you can use the following commands to stop the LaunchAgent and finally delete the script itself (the first line is not always required):
launchctl stop com.krypted.myscript
launchctl unload /Library/LaunchAgents/com.krypted.myscript.plist
launchctl remove com.krypted.myscript
srm “$0”
Now when I have a series of scripts that kicks off, I can either have each remove itself or have a cleanup script that removes all of my installation items and then, like a cartoon pencil, erases itself.