Cyrus Stoller home about consulting

Automating digital cleanup

My desktop and downloads folders used to always feel cluttered. I dreaded cleaning them up in the same way that I dread doing dishes. But, once I realized that I was only organizing them by whether or not I had used particular files recently, I knew that I could easily automate this process. In this post, I wanted to share how I did that, so you can keep clean too.

If you’re on a Mac, you can take advantage of launchd to run this job. Unlike cron, if your computer is asleep when the agent was supposed to run, launchd will run the job at the next possible time. It doesn’t assume that your computer is always running.

The script

In this tutorial, I’m using bash, but feel free to zsh or anything else. The function below looks at the contents of a target directory and moves all files that have not been accessed in the given duration to a temp directory.

#!/bin/bash

function cleanupdir {
  local target_dir=$1
  local duration=$2
  local temp_dirname=$3

  old_files=$(find $target_dir -iname "*" -atime $duration -d 1)

  if [[ -n $old_files ]]; then
    mkdir -p $target_dir/$temp_dirname

    for f in $old_files; do
      if [[ $f != *$temp_dirname ]] && [[ $f != *.DS_Store ]]; then
        mv $f $target_dir/$temp_dirname
      fi
    done
  fi
}

cleanupdir ~/Downloads +7d old
cleanupdir ~/Desktop +14d temp

Once that’s saved, make it executable:

$ chmod +x cleanup.sh

Scheduling

Next, you need to tell launchd or cron to run it. To use launchd, you need to create a plist file. You need to specify a unique label for the job, tell the system how to execute the program, and lastly tell it when to execute. Mine tells my agent to run this job, every morning at 03:12.

<?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>Label</key>
  <string>com.cyrusstoller.cleanup</string>

  <key>ProgramArguments</key>
  <array>
    <string>/Users/cyrusstoller/Documents/cron_jobs/cleanup/cleanup.sh</string>
  </array>

  <key>StartCalendarInterval</key>
  <dict>
    <key>Minute</key>
    <integer>12</integer>
    <key>Hour</key>
    <integer>3</integer>
  </dict>
</dict>
</plist>

By convention, Apple names agents using reverse domain syntax (e.g. com.apple.foobar). While the plist can be named whatever you like, it’d be messy for it to be anything other than the name of the agent. Mine is called: com.cyrusstoller.cleanup.plist.

Warning: If you copy and paste this template, be sure to change the label, otherwise only one of the jobs will work.

Once you’ve saved this file, you need to symlink it to the ~/Library/LaunchAgents/ directory.

# From the ~/Documents/cron_jobs/cleanup directory
$ function absolute_path { echo "$PWD/$1"; }
$ ln -sf $(absolute_path com.cyrusstoller.cleanup.plist) ~/Library/LaunchAgents/

Then you need to load it.

# From the ~/Documents/cron_jobs/cleanup directory
$ launchctl load com.cyrusstoller.cleanup.plist
# OR from elsewhere
$ launchctl load ~/Library/LaunchAgents/com.cyrusstoller.cleanup.plist

# OR using the label
$ launchctl start com.cyrusstoller.cleanup.plist

If you make changes, be sure to unload your plist and then reload it. Otherwise, the changes won’t take effect.

$ launchctl unload ~/Library/LaunchAgents/com.cyrusstoller.cleanup.plist
$ launchctl load ~/Library/LaunchAgents/com.cyrusstoller.cleanup.plist

# OR using the label
$ launchctl stop com.cyrusstoller.cleanup.plist
$ launchctl start com.cyrusstoller.cleanup.plist

You can see the other agents loaded on your system with:

$ launchctl list

Conclusion

From now on, your desktop and downloads folders will clean themselves up every morning. This is just one of many mindless tasks that we do on our computers on a regular basis. Look for ways to automate them, so you can focus your energy on things that matter.


Helpful resources

Category Tutorial