at job seems to be running using /bin/sh though I have a #!/bin/bash

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).

–EDIT–

I am adding the job like this:

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



$ which bash 
/bin/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
Asked By: Ani

||

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.

Answered By: Michael Homer

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

SHELL

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

EOT

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>

Example:

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

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

Answered By: cuonglm

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

or

$ at 1:30 am today
/path/to/my/script.sh
Ctrl+D

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.

Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.