Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

To analyze my own computer usage, not to spy on anyone (although it crossed my mind), I want to have cron capture the current screen every minute.

 * * * * * /bin/bash -c "/usr/sbin/screencapture /somedir/screen.png"

in the crontab will execute and take a screen capture. However, it is totally black because it is not running as, well, me. Any idea how to allow a cron job to capture my screen?

Update: I added a say whoami to the same cron command and it confirms it is running as my user (no sudo or other users involved). I access the crontab from a terminal as myself.

So, it runs as me, but is not attached to my windowing system. Any ideas?

share|improve this question
    
Are you adding this to your system (root) crontab, or your user crontab? –  Richard Hoskins Aug 21 '09 at 4:49
add comment

3 Answers

up vote 10 down vote accepted

If you look at the end of the screencapture manpage, you see it says:

To capture screen content while logged in via ssh, you must launch
screencapture in the same mach bootstrap hierarchy as loginwindow:

PID=pid of loginwindow
sudo launchctl bsexec $PID screencapture [options]

So I think you could do somethig like this in your shell script that cron calls:

#/bin/sh
loginwindowpid=`ps axo pid,comm | grep '[l]oginwindow' | sed -n 's# *\([^ ]*\).*$#\1#p'`
sudo launchctl bsexec $loginwindowpid screencapture /somedir/screen.png

Of course, you'll need your userid set to not need a password for sudo.
That is you'd set in /etc/sudoers with the visudo command

youruserid     ALL=(ALL) NOPASSWD: ALL
share|improve this answer
    
Wonderful solution to my question. Very complete. I had read the man page but same mach bootstrap hierarchy went right over my head so I headed straight to SU to help make sense of it. Thank you very much. –  vgm64 Aug 22 '09 at 21:03
1  
You can eliminate the call to grep -v by making the first call look like grep [l]oginwindow and might be able to eliminate the call to cut by using ps axo comm –  Dennis Williamson Aug 25 '09 at 18:55
    
Very nice solution. –  Laurent Etiemble Dec 15 '09 at 13:39
add comment

If you are going to use sudo to set up cron for another account, you can use the -u switch along with sudo.

example:

sudo -u Your_user crontab -e

else just log into that account and use crontab -e.

share|improve this answer
add comment

As an aside, I use Java for the same job. It starts on boot and I look through the images at the end of the day.

/**
 * Code modified from code given in http://whileonefork.blogspot.co.uk/2011/02/java-multi-monitor-screenshots.html following a SE question at  
 * http://stackoverflow.com/questions/10042086/screen-capture-in-java-not-capturing-whole-screen and then modified by a code review at http://codereview.stackexchange.com/questions/10783/java-screengrab
 */
package com.tmc.personal;

import java.awt.AWTException;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

import javax.imageio.ImageIO;

class ScreenCapture {

    static int minsBetweenScreenshots = 5;

    public static void main(String args[]) {
        int indexOfPicture = 1000;// should be only used for naming file...
        while (true) {
            takeScreenshot("ScreenCapture" + indexOfPicture++);
            try {
                TimeUnit.MINUTES.sleep(minsBetweenScreenshots);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //from http://www.coderanch.com/t/409980/java/java/append-file-timestamp
    private  final static String getDateTime()
    {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd_hh:mm:ss");
        df.setTimeZone(TimeZone.getTimeZone("PST"));
        return df.format(new Date());
    }

    public static void takeScreenshot(String filename) {
        Rectangle allScreenBounds = getAllScreenBounds();
        Robot robot;
        try {
            robot = new Robot();
            BufferedImage screenShot = robot.createScreenCapture(allScreenBounds);
            ImageIO.write(screenShot, "jpg", new File(filename + getDateTime()+ ".jpg"));
        } catch (AWTException e) {
            System.err.println("Something went wrong starting the robot");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Something went wrong writing files");
            e.printStackTrace();
        }
    }

    /**
     * Okay so all we have to do here is find the screen with the lowest x, the
     * screen with the lowest y, the screen with the higtest value of X+ width
     * and the screen with the highest value of Y+height
     * 
     * @return A rectangle that covers the all screens that might be nearby...
     */
    private static Rectangle getAllScreenBounds() {
        Rectangle allScreenBounds = new Rectangle();
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice[] screens = ge.getScreenDevices();

        int farx = 0;
        int fary = 0;
        for (GraphicsDevice screen : screens) {
            Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();
            // finding the one corner
            if (allScreenBounds.x > screenBounds.x) {
                allScreenBounds.x = screenBounds.x;
            }
            if (allScreenBounds.y > screenBounds.y) {
                allScreenBounds.y = screenBounds.y;
            }
            // finding the other corner
            if (farx < (screenBounds.x + screenBounds.width)) {
                farx = screenBounds.x + screenBounds.width;
            }
            if (fary < (screenBounds.y + screenBounds.height)) {
                fary = screenBounds.y + screenBounds.height;
            }
            allScreenBounds.width = farx - allScreenBounds.x;
            allScreenBounds.height = fary - allScreenBounds.y;
        }
        return allScreenBounds;
    }
}
share|improve this answer
    
Major syntax errors with what you posted –  bafromca Dec 18 '12 at 20:18
    
apologies - I've added the missing brackets... –  Joe Dec 18 '12 at 20:51
    
It's still missing one more curly brace at the end. It open class, main(), while, try/catch and then closes try/catch, while, main() but it doesn't close the class. And then it's missing its import statements at the top too. This is what I ended up with just to get it to compile. It still doesn't run: pastebin.com/PrSfhUkS –  bafromca Dec 19 '12 at 17:21
    
Okay - I've given the full code (also avaible at codereview.stackexchange.com/questions/10783/java-screengrab ) - can I ask you to fix the formatting? - I've got to rush off... –  Joe Dec 19 '12 at 21:02
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.