I am a relative Linux novice. I am trying to learn how to use at so that I can schedule tasks to begin at a later time, without using sleep. I have been looking at this previous question for help.

My question is, in the following sample bash script that I have created, why is "Running" never -- as far as I can tell -- printed to the standard output (i.e., my bash console)?


echo "Started"

at now + 1 minutes <<EOF
echo "Running"

echo "Finished"

The only output I see is, for example:

warning: commands will be executed using /bin/sh
job 3 at Fri Jul 12 17:31:00 2013

Is the answer to my question found in the warning? If so, how does /bin/sh differ from the standard output?

  • try this: sleep 3m; echo Running – Jasen Sep 14 '18 at 6:35

Because at does not execute commands in the context of your logged in user session. The idea is that you can schedule a command to run at an arbitrary time, then log out and the system will take care of running the command at the specified time.

Note that the manual page for at(1) specifically says (my emphasis):

The user will be mailed standard error and standard output from his commands, if any. Mail will be sent using the command /usr/sbin/sendmail.

So you should be checking your local mail spool or, failing that, the local system mail logs. /var/spool/mail/$USER is probably a good place to start.

Also note that the "Started" and "Finished" originate from the outer script and in and of themselves have nothing to do with at at all. You could take out them or the at invocation and you'll get essentially the same result.


As @MichaelKjörling has explained it any output that's produced by your at job will be captured and sent to you via email. If you don't have a running MTA - Mail Transfer Agent on your box then the email may be in limbo and you'll not know that at is even attempting to do this.

A MTA, is a program such as sendmail or postfix that can "deliver" email to an appropriate destination. In this case it's going to deliver it to a mail queue (a file under the directory /var/spool/mail) on your local system. Each user on the system can have a queue in this directory.

On my Fedora system if I start up sendmail then local mail delivery can occur. I typically have it off though.

$ sudo service start sendmail

Now we can see that my mail queue for my user account saml is empty:

$ ll /var/spool/mail/|grep saml
-rw-rw----. 1 saml mail       0 Jul 12 19:33 saml

So now we run the at job:

$ at now + 1 minutes <<EOF
echo "Running"
job 96 at Fri Jul 12 19:38:00 2013

We can see that the job is waiting to run with atq:

$ atq
96  Fri Jul 12 19:38:00 2013 a saml

Running it again after a couple of minutes we can see that the at job is complete:

$ atq

Incidentally, with my MTA running I now get this message in my terminal:

You have new mail in /var/spool/mail/saml

So let's check:

$ ll /var/spool/mail/|grep saml
-rw-rw----. 1 saml mail     651 Jul 12 19:38 saml

Yup we've got mail, so let's check it out using mutt:

$ mutt -f /var/spool/mail/saml

We have this in our mail queue's "inbox":

     ss of mutt's inbox

Let's check out this email:

     ss of mutt's msg

And it worked.

  • @MichaelKjörling - mutt rulz 8-) – slm Jul 13 '13 at 12:13

I'm running Debian 8.1 (jessie)
You can have the the 'at' output go to a terminal by using tty.

$ tty

$ at now + 1 min
warning: commands will be executed using /bin/sh
at> echo 'ZZZZZ' > /dev/pts/1
at> <EOT>

One minute later, and 'ZZZZZ' will show up in your terminal...


The above answers are the standard/"right" way to do it.

Another approach that's simpler from a more "end user" point of view is to have any scheduled or background task write its output to a "log" file. The file can be anywhere on your system, but if the task is running as root (from cron, etc.), then somewhere under /var/log is a good place to put it.

I created the /var/log/maint directory and made it readable by everybody and I have a readable file under that called "backup" where I log the output from my backup scripts.

I made my own directory so my files don't get mixed in with things generated by the system.

To put stuff there (in bash):

echo "my message" >> "${BACKUP}"

The >> causes the messages to be appended to the file instead of overwriting it each time.

If my script has a lot of output, I use a script or function for output so everything gets done the same. Below is my current (overkill version): (the VERBOSE stuff is there for when I'm running the script from a terminal and want to see what's going on for debugging purposes.)

## backup_logger
## backup system logging module
## Copyleft 01/20/2013 JPmicrosystems
## Usage is ${SCRIPT_NAME} [-v] [<caller> <log message text>]
## If present, -v says log to console as well as to the log file
## <caller> is the name of the calling script
## If <caller> <log message text> is not present, write a blank line to the log

## Must be placed in path, like ~/bin
## If log is owned by root or another user, then this must run as root ...
## If not, it just aborts

##source "/home/bigbird/bin/bash_trace"  ## debug
SCRIPT_NAME="$(basename $0)"
USAGE="Usage is ${SCRIPT_NAME} [-v] [<caller> <log message text>]"

if [ "${1}" == "-v" ]

##LOGGING=0  ## debug
##VERBOSE=1  ## debug

## Only zero or two parameters allowed - <caller> <log message text>
if [ "$#" -eq 1 ] || [ "$#" -gt 2 ]
  echo "${USAGE}"
  if [ ! -w "${SYSLOGFILE}" ]
    touch "${SYSLOGFILE}"
    if [ $? -ne 0 ]
      echo -e "$(date) ${1} ${2}"
      echo "${SCRIPT_NAME} Can't write to log file [${SYSLOGFILE}]"
      exit ${RC}

  if [ -n "${1}" ]
    (( LOGGING )) && echo -e "$(date) ${1} ${2}"  >> "${SYSLOGFILE}"
    (( VERBOSE )) && echo -e "$(date) ${1} ${2}"
    (( LOGGING )) && echo "" >> "${SYSLOGFILE}"
    (( VERBOSE )) && echo ""

exit $RC

Edit: Simplistic at example which writes to a user file

Haven't used this in forever, so I figured it out with a couple of simple scripts.

The first script just schedules the event using at. The command itself could just be typed into a terminal, but I'm lazy - especially when I have to do it multiple times while testing it without fooling with command history.

## mytest_at_run
## Schedule a script to run in the immediate future
echo "/home/bigbird/bin/mytest_at_script" | at 00:56

The second script is the one which is scheduled to run

## mytest_at_script
## The script to be run later
echo "$(date) - is when this ran" >> /home/bigbird/log/at.log

I created both scripts in a text editor, saved them, and then made them each executable using chmod 700 script-file-name. I put them both in my $HOME/bin directory for convenience, but they could be anywhere my user has full access. I use 700 for any script that's just for testing, but on a single user system, it could just as well be 755.

I already have a directory called /home/bigbird/log to save the output from mytest_at_script. This can also be anywhere your user has full access. Just make sure it exists before the script runs or have the script create it.

To run it, I just made sure the time for the at command in mytest_at_run was a little bit in the future and then ran it from a terminal. I then waited until it ran and examined the contents of $HOME/log/at.log.

bigbird@sananda:~/bin$ cat ~/log/at.log
Fri Sep 14 00:52:18 EDT 2018 - is when this ran
Fri Sep 14 00:56:00 EDT 2018 - is when this ran

A few notes:

Even though I'm running at from my user, it doesn't know my environment such as my PATH and my home directory, so I don't assume that. I use full paths like I would for any cron job. And if I ever want to make it a cron job, I won't have to change anything just to make it run.

I used >> in mytest_at_script to append output to the log file instead of > which would have replaced it on every run. Use whichever one suits your application best.

  • can you provide me any example to write output to log file using AT command, I'm trying in following way but no result, at now + 1 min at> echo ""hello" >> /home/camsarch/cams_scripts/texsttest.txt at> <EOT> – Pavan Kumar Varma Sep 7 '18 at 8:31
  • @PavanKumarVarma - added a simplistic (tested) example using at to write to a file. Looks like you got the calling sequence backwards in your example. I'm not very good at telling at when to run the job, so I just hard-coded a time in the very near future. – Joe Sep 14 '18 at 5:48

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.