I am trying to run a job using at, and I have a bash script (I do have #!/bin/bash as the first line), but the job fails because of use of [[ and ]] in the script, I see the following in the mail that it generates:

=sh: 58: [[: not found
=sh: 58: [[: not found
=sh: 58: [[: not found
=sh: 58: [[: not found
=sh: 58: [[: not found

The /bin/sh is a link to dash, but if I have the she-bang line as #!/bin/bash in my script - should it not use bash instead?

P.S If I just run the script on my bash prompt - it works fine with no errors (and it has executable permissions).


I am adding the job like this:

$ at 1:30 am today -f /path/to/my/script.sh

$ which bash 

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 30  2012 /bin/sh -> dash

$ uname -a
Linux server1 3.5.0-46-generic #70~precise1-Ubuntu SMP Thu Jan 9 23:55:12 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
  • Can you add to question the at command that you type. Aug 25, 2014 at 9:50

3 Answers 3


POSIX defined that at can use SHELL environment variable as alternative to /bin/sh, but did not restrict it:


Determine a name of a command interpreter to be used to invoke the at-job. If the variable is unset or null, sh shall be used. If it is set to a value other than a name for sh, the implementation shall do one of the following: use that shell; use sh; use the login shell from the user database; or any of the preceding accompanied by a warning diagnostic about which was chosen.

Some implementation of at can give you ability to chose which shell you want to run, like -k for Korn shell, -c for C-shell. And not all implementation of at allow SHELL to substitute sh. So POSIX also guaranteed the reliable way to use another shell is explicit call it:

Some implementations do not allow substitution of different shells using SHELL. System V systems, for example, have used the login shell value for the user in /etc/passwd. To select reliably another command interpreter, the user must include it as part of the script, such as:

$ at 1800

myshell myscript


job ... at ... $

A simple way, using bash to run your script is passing bash script as stdin to at:

echo "bash /path/to/yourscript" | at <time>


echo "bash /path/to/yourscript" | at 16:30

will run bash /path/to/yourscript at 16:30 today.

  • This worked!, but somehow, I am not getting a mail - at the end of the script, I have a mutt invocation to send out a mail to me, I have also configured postfix, but apart from that - the script execution seems to be done.
    – Ani
    Aug 25, 2014 at 10:36
  • oops! the mail was sent, OL moved it to junk! :(. sorry.
    – Ani
    Aug 25, 2014 at 11:02

at and batch:

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

POSIX defines at's input as:

a text file consisting of commands acceptable to the shell command language described in Shell Command Language.

That is, it's required to be a POSIX sh script. Bash allows Bashisms through even when it's run as sh, but dash is strict. The script isn't run as an executable, but directly with sh, so an arbitrary binary or a Python script won't work either, for example.

What you may be able to do, though, is to force yourself into bash anyway. Something like:

[ "$BASH_VERSION" ] || exec bash "/path/to/script"

at the top of the file should have the script re-execute itself with bash when it isn't already being interpreted that way. The shell won't generate syntax errors for code it that execution doesn't get to, so the later uses of [[ won't matter. You may be able to use $0 instead of the path, but it seems to be inconsistent across at implementations and none of the specifications imply it should work, so the path will be more reliable.

  • OMG! I have to force re-execute in bash!, I could have never imagined that method! I'll try it now.
    – Ani
    Aug 25, 2014 at 9:46
  • I added [ $BASH_VERSION ] || exec /bin/bash "$0" as the first line in my script, but in the mail, I see this error /bin/sh: /bin/sh: cannot execute binary file, not sure why!
    – Ani
    Aug 25, 2014 at 10:36

My answer is similar to Gnouc’s, but I believe I have a better explanation of the “Why?”  When you say at … -f /path/to/my/script.sh, you are telling at to read /path/to/my/script.sh.  It copies your script somewhere (probably somewhere under /var/spool/cron) so that atd, the at jobs daemon, can pass the script’s contents to /bin/sh.  At this point, the #!/bin/bash she-bang line is just a comment, and your [[…]] usage is an error.

What you want to do is not give at the contents of your script, but give it the name, by

$ echo /path/to/my/script.sh | at 1:30 am today


$ at 1:30 am today

That way, the /bin/sh will see /path/to/my/script.sh and will execute it as a command.  And then the she-bang line will do its job, causing bash to be invoked.

P.S. My answer (like Gnouc’s) has the “feature” that, if you change your script between now and 1:30 am today, atd will run the modified version.  (This is in contrast to your approach, using -f, where at makes a copy of your script when you run at.)  In particular, if you delete or rename the script, nothing will run.

  • I think cron is not issue here. Some implementation of at can give you ability to chose which shell you want to run, like -k for Korn shell, -c for C-shell.
    – cuonglm
    Aug 25, 2014 at 18:37
  • @Gnouc: I don’t understand what your point is. cron is the daemon that runs at jobs, so your answer is all about what shell cron uses (you just don’t say that you’re talking about cron). And your statement about at looks like it should maybe be a part of your answer. Aug 25, 2014 at 18:43
  • at jobs queue is run by atd daemon. Nothing about cron here. Updated my answer.
    – cuonglm
    Aug 25, 2014 at 18:46
  • @Gnouc: OK, I updated my answer. Aug 25, 2014 at 19:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .