36

I was studying code in which the at command is used. I looked around and found that it is used to execute batch jobs. It is used to schedule jobs. It is given, as its input, a command, and a time, relative or absolute.

So, my first question is: why is the at command used? Under which circumstances does one need to use at? I have encountered it when there was some bash script code trying to uninstall software and when some background services were to be restarted.

My second question: What is the difference between having any command executed as a batch job and having a command executed in calling command directly (or in subshell)?

46

Bernhard's reply is correct: in multi-user systems, the ability to execute heavy programs at some ungodly hours of the night is especially convenient, for both the person submitting the job, and his coworkers. It is part of "playing nice".

I did most of my Ph.D. computations this way, combining the script with the nice command which demoted the priority of my work whenever other people were keeping the machine busy, while leaving intact its ability to hog all the system resources at night.

I used the very same command to check whether my program was running, and to restart it if necessary.

Also, you should keep in mind that at was written way before screen, tmux, and so on, so that it was a simple way to have a detached shell, i.e., one that would not die once you logged off the system.

Lastly, you should also notice that it is different from cron, which also has been around for a long time. The difference lies in the fact that at is occasional, while cron, being so repetitive, is more suited for system jobs which really need to be executed forever at fixed intervals: in fact, at gives you your own environment, with your own settings (and choices) of environment variable, while cron uses a minimal set of environment variables (just check the difference in PATH, as an example).

  • 15
    Also worth pointing out as another difference with cron, is that at retains your environment the way it was when the job was scheduled: same working directory, environment variables, ... – Carlos Campderrós Oct 28 '13 at 10:19
  • 10
    There's also batch, which is nearly identical to at, but will wait for a low load instead, and apparently, at -q z will nice the job by itself, whereas at -q Z will wait for the time, then wait for load to drop, and nice the job as well. Wow, what a load of seldom-used features! – Ulrich Schwarz Oct 28 '13 at 12:29
16

I use the at command when I need to do some heavy processing on data, which I want to have executed during the night, when I am not behind my computer. Of course I could start the process just after I leave, but this is something I tend to forget.

The result of the command is not different from regularly execution of the script or command.

15

When you have questions such as this always consult the man pages. They can be very enlightening.

What it does

excerpt from at man page

NAME
       at, batch, atq, atrm - queue, examine or delete jobs for later execution

DESCRIPTION
       at  and  batch  read  commands  from  standard  input or a specified file
       which are to be executed at a later time, using /bin/sh.

Usage

The usage of the tools:

Usage: at [-V] [-q x] [-f file] [-mldbv] timespec ...
       at [-V] [-q x] [-f file] [-mldbv] -t time
       at -c job ...
       atq [-V] [-q x]
       atrm [-V] job ...
       batch

at includes 4 commands (at, atq, atrm, and batch). You use at and batch to schedule the jobs, atq to see what's scheduled, and atrm to remove a job prior to it running.

$ at -f <cmd> timspec

Timespec

The time to run the at job can be specified in different ways.

excerpt form at man page

At allows fairly complex time specifications, extending the POSIX.2 standard. It accepts times of the form HH:MM to run a job at a specific time of day. (If that time is already past, the next day is assumed.) You may also specify mid‐ night, noon, or teatime (4pm) and you can have a time-of-day suffixed with AM or PM for running in the morning or the evening. You can also say what day the job will be run, by giving a date in the form month-name day with an optional year, or giving a date of the form MMDD[CC]YY, MM/DD/[CC]YY, DD.MM.[CC]YY or [CC]YY-MM-DD. The specification of a date must follow the specification of the time of day. You can also give times like now + count time-units, where the time- units can be minutes, hours, days, or weeks and you can tell at to run the job today by suffixing the time with today and to run the job tomorrow by suffixing the time with tomorrow.

Examples

Say you have this shell script.

$ cat mycrontest.sh

#!/bin/bash
 echo "It is now $(date +%T) on $(date +%A)"

Sample run:

$ ./mycrontest.sh
It is now 18:37:42 on Friday

Sample at job submissions:

$ at -f mycrontest.sh  10pm tomorrow
job 14 at Sun Jul  8 22:00:00 2007

$ at -f mycrontest.sh 2:00 tuesday
job 15 at Tue Jul 10 02:00:00 2007

$ at -f mycrontest.sh 2:00 july 11
job 16 at Wed Jul 11 02:00:00 2007

$ at -f mycrontest.sh 2:00 next week
job 17 at Sat Jul 14 02:00:00 2007

References

  • I seem to have a very different version of at available on my Cygwin installation - it doesn't seem linked to batch, no short options at all are supported, there is no quiet option, and no man or info pages are included. – Hashim Sep 24 '18 at 4:10
  • @Hashim - cygwin is it's own beast. – slm Sep 24 '18 at 4:14
6

You can execute batch jobs in UNIX / Linux using any one of the three commands — at, batch or cron.

Schedule an at job using specific date and time

Syntax:

    $ at time date
For example, to schedule a job at 11 am on May 20, use the following at command.

    $ at 11 am may 20
  • Yes, I have that understanding of "at" and its usage. Other people have answered it more relevantly. – Akshay Patil Oct 29 '13 at 5:23
5

Your network administrator informs you that some maintenance will occur to your web servers starting at 7pm and finishing by 2am. You want to serve a maintenance notification beforehand, and you want maximum uptime from your system. Are you going to stay up all night, ready to run various commands, and then start it up again later? No, you'd want to use at to schedule these tasks, then go to bed / play skyrim and forget about it.

1

at can also be a really handy way to fire off reminders. My current dev machine is running OSX, so at and the simple notify.bash that I cobbled together can be really helpful:

$ at 5pm
notify.bash -t 'Work is over' -m "Don't forget to rollback INT environment"
^D
$ at now + 15 minutes
notify.bash -m 'Check tests' -l 'http://integration.example.com/jobs/XXXX'
^D
$ at now + 10 minutes
notify.bash -m 'Check the fridge, pudding should be done!'
^D

notify.bash

#!/bin/bash

DEFAULT_TITLE='Hey! Listen!'
TITLE="$DEFAULT_TITLE"
LINK=
MESSAGE=

function args.help () {
    local error="$1"
    if [ "$error" ]; then
        echo >&2 "$error"
    fi
    cat >&2 <<EOF
Usage $0 <options>

Displays a message using an Applescript notification box

Options
-------

--title <text>    Sets the title, otherwise the default is used ("$DEFAULT_TITLE")
 -t     <text>    Alias for --title

--link  <url>     Add a button to open a link
 -l     <url>     Alias for --link

--body  <text>    Set the message body
 -m     <text>    Alias for --body
EOF
}

function args.verify-not-empty () {
    local value="$1"
    local varname="$2"

    if [ "$value" ]; then
        echo "$value"
    elif [ "$varname" ]; then
        args.help "$varname cannot handle an empty argument"
        exit 1
    else
        args.help \
            "The programmer forgot to include context, something was empty which shouldn't have been, but I can't tell you much more than that. Sorry :("
        exit 1
    fi
}

function args.parse () {
    while [ "$1" ]
    do
        case "$1" in
            '-t' | '--title')
                shift
                TITLE=$(args.verify-not-empty "$1" title)
                shift
                ;;
            '-l' | '--link')
                shift
                LINK=$(args.verify-not-empty "$1" link)
                shift
                ;;
            '-m' | '--body')
                shift
                if [[ "$1" = '-' ]]; then
                    MESSAGE=$(cat -)
                else
                    MESSAGE="$1"
                fi
                MESSAGE=$(args.verify-not-empty "$MESSAGE" body)
                shift
                ;;
            *)
                args.help "Unrecognized argument: $1"
                exit 1
        esac
    done
    if [[ ! "$MESSAGE" ]]; then
        args.help "Message body was not specified"
        exit 1
    fi
}

function message.display-no-link () {
    osascript > /dev/null <<EOF
tell application "Finder"
  activate
  display alert "$TITLE" ¬
          message "$MESSAGE" ¬
          buttons { "Acknowledge" } ¬
          default button "Acknowledge"
end tell
return
EOF
}

function message.display-with-link () {
    osascript > /dev/null <<EOF
tell application "Finder"
  activate
  display alert "$TITLE" ¬
          message "$MESSAGE\n\nClick 'Open Link' to go to $LINK" ¬
          buttons { "Acknowledge", "Open Link" } ¬
          default button "Open Link"
          set response to button returned of the result
          if response is "Open Link" then open location "$LINK"
end tell
return
EOF
}

function message.display () {
    if [ "$LINK" ]; then
        message.display-with-link
    else
        message.display-no-link
    fi
}

args.parse "$@"
message.display

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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