There are three straightforward other options. One is a bit fragile and relies on implementation details of the shells, another uses here documents to provide the script to bash
inline, and the other just uses -c
to pass a single line in.
Most reliably and portably, use a here document:
$ at now
warning: commands will be executed using /bin/sh
at> bash <<'EOF'
at> echo {1..5} >/tmp/output
at> EOF
at> <EOT>
job 24 at Mon Mar 23 20:41:20 2015
$ cat /tmp/output
1 2 3 4 5
<<word
declares a here document that is provided as standard input to bash
and lasts until word
. By quoting 'EOF'
the document is not subject to expansion by the shell, so you can write a $
in the body without dash
eating it. Your script can include anything other than EOF
(or your word of choice) at the start of a line.
This is really the approach I'd recommend — you can very nearly write it exactly as though you'd been using bash
all along, with just an extra line at the start and end to show there's anything going on.
If it's really just a single line, just use bash -c
to pass a single command to run:
$ at now
warning: commands will be executed using /bin/sh
at> bash -c 'echo {1..3} >/tmp/output'
at> <EOT>
job 25 at Mon Mar 23 20:50:03 2015
$ cat /tmp/output
1 2 3
That can be a bit of a hassle when you have quotes to use inside the command as well.
Most hackishly: atd
generally sends jobs to the shell as standard input (but I don't believe it's required to). Shells generally read standard input line-by-line (but they are not required to behave in that way).
If your implementations do behave that way then you can perform a nasty trick to run your job under another shell:
$ at now
warning: commands will be executed using /bin/sh
at> bash
at> echo {1..10} >/tmp/output
at> <EOT>
job 22 at Mon Mar 23 20:40:00 2015
$ cat /tmp/output
1 2 3 4 5 6 7 8 9 10
This works because sh
reads the first line and executes bash
, and bash
then gets to read the rest of standard input as its commands. This is pretty fragile, but is the least intrusive version when it works.
dash
itself is notably fiddlier in this area than many shells, and filling up an internal buffer is more important to it. Other simplistic shells, such as BusyBox's sh
, tend to have the line-buffering behaviour.
Finally, although you're never required to use a separate script file, in many cases it actually will be the better option rather than trying to be too clever about things. When your jobs are single-use or programmatically-generated, these are reasonable options, but any other time sucking it up and using a standalone script is probably worth it in maintenance terms.
I really can't recommend the stdin exploitation of the last option at all, but it's a cute trick.