Andy Taylor

Andy Taylor

Better OS X Screenshots With Shell Scripts

I take heaps of screenshots. The tool that’s built into OS X does the job, with a couple of caveats: screenshots take over your desktop and they aren’t sharable by default.

I flirted with lots of software (Dropbox, Cloud, Skitch, droplr etc.) in an attempt to remove these issues, but nothing did exactly what I wanted. So I wrote a Shell script that makes use of the system Screencapture command line app with a few custom settings:

dropboxuser=21267 # Replace with your ID
directoryname=shots
filename=shot_`date '+%Y-%m-%d_%H-%M-%S'`.png
path=~/Dropbox/Public/$directoryname/
mkdir -p $path
screencapture -o -i $path$filename
open --reveal $path$filename
publicurl=https://dl.dropboxusercontent.com/u/$dropboxuser/$directoryname/$filename
printf $publicurl | pbcopy

When triggered it will capture a screenshot, put it in your Dropbox Public directory, reveal it in Finder and copy a sharable URL to the clipboard.

This means clutter is removed from the desktop, screenshots are all filed together, you have quick access to the file and a direct link is on your clipboard.

Trigger With a Hotkey

You can trigger a Shell script with a hotkey by creating a OS X System Service then assigning a shortcut to it.

  1. Open Automator.app.
  2. Create a new ‘Service’.
  3. Change ‘Service receives selected text’ to ‘Service receives no input’.
  4. Search for ‘Run Shell Script’ and add it.
  5. Paste this script in (replace my Dropbox ID with yours).
  6. Save it. It should go in ~/Library/Services.
  7. Go to System Preferences, then ‘Keyboard’, select ‘Shortcuts’ then ‘Screen Shots’ in the sidebar.
  8. Uncheck ‘Save picture of selected area…’ so you can re-use that shortcut.
  9. Select ‘Services’ from the sidebar and find the service you created. It should be at the bottom of the list under ‘General’.
  10. Add a shortcut. Use Cmd + Shift + 4 to replace the system version.

Line by Line Breakdown and Customisation

This script does exactly what I want it to do. But it’s fairly easy to change almost everything it does. I’ll break it down line by line:

Dropbox Setup

The only thing you need to set is your Dropbox user ID. To find yours, you can share something from your Public directory. It’s the number following /u/ in the URL.

dropboxuser=21267

Set the name of the directory where screenshots will be saved. It’ll live inside your Dropbox Public directory. Setting this to shots will result in ~/Dropbox/Public/shots. This directory name is also part of the sharing URL.

directoryname=shots

Set the filename for each screenshot. I’ve included the full date and time to maintain order.

filename=shot_`date '+%Y-%m-%d_%H-%M-%S'`.png

Create the directory if it doesn’t exist. $path is set as a variable so we can use it later. The -p flag creates the full path, but it also stops the script from throwing an error if the directory exists.

path=~/Dropbox/Public/$directoryname/
mkdir -p $path

Take the Screenshot

screencapture -o -i $path$filename

The -i flag sets interactive mode so you can select a region of the screen. Hit space to change to window selection mode.

The -o flag removes the window shadow from window selections. If you dig that, remove it.

Remove -o -i for full-screen screenshots, or use -m to force a multi-monitor setup to only capture the main monitor.

Reveal in Finder

Revealing it in Finder means you don’t need to locate the file.

open --reveal $path$filename

Alternatively, you could open it in a Mac app that accepts images as input, like Preview or Tweetbot. The -a flag ‘Opens with the specified application’; you can provide a direct path to an app, but using the app name seems nicer.

open -a 'Preview' $path$filename

If you don’t want to reveal it in Finder you could simply remove that line. For quick access to the screenshot directory you could make another script/hotkey combo. I use Cmd + Shift + 2 for this.

open ~/Dropbox/Public/shots/

Build Dropbox Public URL

By looking at the $variables in the URL below, you can see how a Dropbox public URL is formed. We’re simply replacing those variables with output of the script.

publicurl=https://dl.dropboxusercontent.com/u/$dropboxuser/$directoryname/$filename

At this point you could also open the URL in your default browser, but it will 404 until the file has finished uploading.

open $publicurl

Copy URL to Clipboard

If you printf the URL, you can then pipe (send) it to pbcopy which copies it to the clipboard.

printf $publicurl | pbcopy

Alternatively you could copy a Markdown/HTML image tag to the clipboard.

printf "![]($publicurl)" | pbcopy
# You may need to escape the `!` by putting a `\` before it.
printf "<img src="$publicurl" alt="" />" | pbcopy

I prefer to keep the raw URL on my clipboard and use another script/hotkey combo to convert it to Markdown.

printf "![](`pbpaste`)" | pbcopy
# You may need to escape the `!` by putting a `\` before it.

Permanence

So I can periodically clear out the shots directory, I have a directory called keep inside shots for screenshots I want to keep. The script below (when used as part of an Automator Service) takes the currently selected Finder item, moves it to the keep directory and copies the Dropbox URL to the clipboard.

n=0
while read line ; do
  let n=n+1
  filename=`basename "$line"`
  dropboxuser=21267 # Replace with your ID
  directory=/shots/keep/ # This is the full path iside your Public Dropbox directory. The slashes are important.
  path=~/Dropbox/Public$directory
  mkdir -p $path
  date=$(date +%H-%M-%S)-
  if [ -f $path$filename ] ;then
    mv $line $path$date$filename
    printf https://dl.dropboxusercontent.com/u/$dropboxuser$directory$date$filename | pbcopy
  else
    mv $line $path$filename
    printf https://dl.dropboxusercontent.com/u/$dropboxuser$directory$filename | pbcopy
  fi
done

If a file with the same name exists, it prepends the time so the it isn’t overwritten. If you don’t want to commit to moving the file you could change mv $line ... to cp $line ... to copy instead. This can be triggered on any file, not just ones in the shots directory.

Create the Automator Service

  1. Open Automator.app.
  2. Create a new ‘Service’.
  3. Change ‘Service receives selected text’ to ‘Service receives no input’.
  4. Search for ‘Get Selected Finder Items’ and add it.
  5. Search for ‘Run Shell Script’ and add it.
  6. Paste in this script and save.
  7. Create a hotkey in Keyboard System Preferences as mentioned above.

Have a comment? @me on Twitter.