25

I'm trying to run a command at a specific time. I've looked at the "at" command, but I don't know how to get it working...

Here's what I do:

at 1843 (Enter)
php /run/this/script.php (Ctrl+D)

But how do I do this in a bash script? I mean, I need to press enter and "Ctrl+D" to set up the delay... How to do this in a script?

Any suggestions most welcome.

Thanks in advance,

hlovdal
  • 26,565
  • 10
  • 94
  • 165
Eamorr
  • 9,872
  • 34
  • 125
  • 209
  • 3
    Cron is for intervals? I mean, I don't want to run at scheduled intervals, rather at specific times. – Eamorr Apr 20 '11 at 17:43
  • A specific time is a kind of interval, if you want it at that time every day or at the beginning of the month. Also, sometimes it makes more sense to have it as a regular cron job which checks to see if it needs to run, instead of having some script schedule it; what happens if the script is inadvertently twice? – geekosaur Apr 20 '11 at 17:55
  • Late to the party, but if you'd like to run the 'at' command the same way you'd run the `sleep` command whilst using a specific time instead of duration, then you set the following (which I use myself) in your shell's _rc_ file: `at() {sleep \`datediff $(date +%H:%M:%S) $(sed -r 's/([0-9]{2})([0-9])/\1:\2/' <(echo $1)) | sed -r 's/s$//'\`}` – Example: `at 15:10; ls` or `at 1510; ls` – Faxopita Mar 29 '23 at 14:10
  • Improved: `at() {[[ -n \`echo $1 | grep -o --perl "^\d{2}:?\d{2}\b"\` ]] && { HM=\`sed -r 's/([0-9]{2})([0-9])/\1:\2/' <(echo $1)\`; sleep \`[[ "$HM" > "$(date +%H:%M:%S)" ]] && datediff -f %S $(date +%H:%M:%S) $HM || datediff -f %S $(datediff -f %H:%M:%S $HM $(date +%H:%M:%S)) 24:00\`; } || { echo "Usage: at hh[:]mm && command"; (exit 1); }}` – Faxopita Mar 31 '23 at 14:23

5 Answers5

34

You can echo your command into at as input:

echo "/usr/bin/php /run/this/script.php" | at 18:43
Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
  • Hey, thanks for that. I tried to run firefox at 1847, but it didn't work. Here's the command: echo "/usr/bin/firefox" | at 1847 – Eamorr Apr 20 '11 at 17:47
  • Try it as `18:47` assuming you mean 6:47 pm – Michael Berkowski Apr 20 '11 at 17:49
  • Hey, I tried as 18:47 too, both syntaxes appear to be valid and are added to the job queue. Firefox doesn't come up though... – Eamorr Apr 20 '11 at 17:50
  • My test didn't work either with firefox. That may have to do with X server environment. Your initial example with a PHP script would work though. – Michael Berkowski Apr 20 '11 at 17:52
  • Ok, that's reassuring. Although I do need to interact with X server... I'll want to use xnee to automatically press a few buttons on my web browser ;( – Eamorr Apr 20 '11 at 17:53
  • @Eamorr I don't know if I can help further then. I don't know how to make `at` talk to X and anything I've tried doesn't work. sorry. – Michael Berkowski Apr 20 '11 at 17:58
  • this works for me if i remove the echo and just write: command | at 18:43 – Robin Manoli Feb 15 '14 at 19:52
  • @ribot but with what command? Just doing `command | at...` would pipe the immediate output of `command` into `at`. – Michael Berkowski Feb 15 '14 at 20:11
  • @MichaelBerkowski, can you please tell me how to cancel an assigned job? – user22180 Jun 25 '14 at 12:32
  • 1
    @user22180 Jobs scheduled with `at` are assigned a job id, which you can find by running `atq` or reading the output from `at`, which would be something like `job 22 at ....`. Then use the `atrm` command to remove that job from the queue by its id. Check the man pages: `man at` – Michael Berkowski Jun 25 '14 at 13:29
13

You could try this:

at 1843 <<_EOF_
php /run/this/script.php
_EOF_

edit if what you want to do is run Firefox, try this:

at 1843 <<_EOF_
DISPLAY=:0.0 /usr/bin/firefox
_EOF_
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 2
    Well when "at" runs the program, it may be that it doesn't have access to the X display; you might try making sure that the "DISPLAY" environment variable is set to ":0.0" or something *inside* the "at" script, before you run the browser. – Pointy Apr 20 '11 at 18:00
8

In bash or zsh you can say

at 1843 <<< 'php /run/this/script.php'

Failing that, you need to use a here document:

at 1843 <<EOF
php /run/this/script.php
EOF

You might also want to look into cron for regularly scheduled jobs; the crontab entry would look like

43 18 * * * php /run/this/script.php

(EDIT: whoops, helps to recall which version of at. I think that may have been a local mod.)

geekosaur
  • 59,309
  • 11
  • 123
  • 114
  • Hi, when I run your at command, I get: syntax error. Last token seen: p Garbled time – Eamorr Apr 20 '11 at 17:48
  • No problem, you wouldn't know how to open firefox at a future time would you by any chance? i.e. /usr/bin/firefox isn't working... – Eamorr Apr 20 '11 at 17:59
  • 2
    Neither `at` nor `cron` normally has access to the window system. You should be able to get the values of `$DISPLAY` and `$XAUTHORITY` and set then in the job with `env`; often just `env DISPLAY=:0 /usr/bin/firefox` will work as the command. – geekosaur Apr 20 '11 at 18:01
  • brilliant! Thanks so much for that. I got it working by adding the line export DISPLAY=:0.0 to my script... – Eamorr Apr 20 '11 at 20:35
2

echo "php /run/this/script.php" | at 18:43

drysdam
  • 8,341
  • 1
  • 20
  • 23
1

The at command is not installed by default to the systems I work (Ubuntu, RHEL) and I don't have permissions to install new software, so I use scripts that combine bash and awk in order to achieve the at functionality as follows:

#! /bin/bash

res=""
while [ ! $res ]; do

    res=$( date | awk -v hour=$1 -v min=$2 '{ 

        split($4, tmp, ":" );

        if( (tmp[1] == hour) && (tmp[2] == min) )
        {
            print "ok";   
        }
        else
        {
            print "";
        }

    }' )

done

./atReplacement.sh $HOUR $MIN; [OTHER_COMMANDS]

funk
  • 2,221
  • 1
  • 24
  • 23
  • Why don't you use `sleep`? If I understand well, your script will run two commands (`date` and `awk`) again and again until the expected time! You should rather compute the remaining time to wait and use `sleep` instead. – Thomas Baruchel May 17 '21 at 15:08