4

Recently I started the process of gradual switching my shell to nu and because of it I thought about assigning its path to SHELL in cron.

Having read a good part of the manual at man 5 crontab, I took a look at PATH and copied the convention of using : in between the values attempting to assign two shells to SHELL:

SHELL=/bin/bash:/home/jerzy/.cargo/bin/nu

It does not work, the scripts from my crontab are not doing their job. Whereas either SHELL=/bin/bash and SHELL=/home/jerzy/.cargo/bin/nu works fine.

Can I assign two shells to SHELL? Does it even make sense to do so?

6
  • 13
    What are you hoping to achieve by this? Jul 10, 2021 at 17:39
  • @Gordon Nu does not yet support many features available in Bash, as multiline commands with `\` . I was hoping that in such case Bash would handle them.
    – John Smith
    Jul 10, 2021 at 17:43
  • 6
    Have you considered just having each entry directly call a script that does what you desire? Provided you have a proper #! line at the start of the script and the script file is executable, the shell configured in cron simply does not matter. Jul 11, 2021 at 1:55
  • @Austin I have. Most of my entries are already scripted, not all, though.
    – John Smith
    Jul 11, 2021 at 6:12
  • 2
    The : separator is specific to environment variables which take lists, like PATH and a few similar variables (NODE_PATH, LD_LIBRARY_PATH...), where there is a simple test to try different items of the list in order: does the file we're looking for exist in that directory or not?
    – jcaron
    Jul 12, 2021 at 16:28

2 Answers 2

25

No, you can’t assign two shells to SHELL: cron needs to know which shell to start, there can only be one. The SHELL variable in crontab doesn’t specify possible shells, it specifies the shell to use. cron reads the value in SHELL, if any, and uses that as the command to run; it doesn’t interpret : or any other symbol.

A fallback can’t work either: if something fails with nu, cron can’t know whether it failed because of nu or something else. Most scripts are written for a given interpreter (specified in their shebang), you can’t try running them with one and again with another. Likewise, crontab entries are written with the specified SHELL in mind (if not the default /bin/sh).

9

No, having multiple shells in SHELL doesn't make sense, for the reasons @Stephen described in their answer. But, the SHELL variable only controls the shell cron uses to run the immediate command part in the crontab line; and at least in Vixie cron, which you often have on Linux systems, SHELL can be changed in the middle of crontab. The Debian man page for crontab(5) says:

The crontab file is parsed from top to bottom, so any environment settings will affect only the cron commands below them in the file.

That sentence looks like it might have been added by Debian, but it seems to work the same on the CentOS system I tried. But as noted in comments by Toby Speight, environment variable assignments in crontab aren't a POSIX feature at all, so YMMV.


So, regardless of the cron, you should be able to do something like this:

* * * * * /path/to/somescript.py maybe 
* * * * * /path/to/otherscript.pl some
* * * * * /path/to/thirdscript.sh args

where the scripts have the proper hashbang lines, e.g. #!/usr/bin/python3, #!/usr/bin/perl, #!/bin/bash or whatever. SHELL just needs to be set to something that can take /path/to/somescript.py maybe etc. as a command and run that script with an argument. Most shells support the trivial stuff identically, so if you put the complicated stuff inside separate scripts and keep the crontab lines simple, you can use whatever shell or scripting language in the scripts themselves.


And, if you need to use different shells in the immediate crontab commands, you can do this, at least in Vixie cron:

SHELL=/bin/bash
* * 8-14 * * if test "$(date +\%w)" = 0; then echo $BASH_VERSION > /tmp/bashtest; fi
SHELL=/usr/bin/fish
* * 8-14 * * if test (date +\%w) = 0; echo $FISH_VERSION > /tmp/fishtest; end

Both check if the day is Sunday, and print the shell version if it is, one using Bash, one using fish. (That's only an example, of course, but because of the way the cron time settings work, running on the first/second/last particular weekday of a month is one of the common cases where you might want to use shell code on the crontab command.)

Also, as an aside, you mentioned in the comments that Nu doesn't support multiline commands with \, and was hoping you could use Bash there. Note that you can't have multiline commands in the crontab line: The command itself must be on just one line in the file, and while cron takes a % sign as a line break, the lines following the first are sent to the standard input of the command. (And that's why we need to escape the % used in the format string for date above.)

4
  • Is it specified that SHELL= lines can be used multiple times like that? That it works for you might just be a feature (or implementation artefact) of the particular cron you used. Of course, one can always use a shell itself as the command to run. (e.g. /bin/bash -c 'if test …') Jul 12, 2021 at 9:42
  • @TobySpeight yes. You can use intersped "mailto=" lines to send the output of anything in the following section to different recipients, too.
    – Criggie
    Jul 12, 2021 at 11:00
  • 1
    @TobySpeight, for Vixie cron, at least the Debian man page says that "The crontab file is parsed from top to bottom, so any environment settings will affect only the cron commands below them in the file.". That sentence might be a Debian addition, but it works the same on the ancient CentOS system I tried on. If there's other implementations that do it differently, I don't know.
    – ilkkachu
    Jul 12, 2021 at 11:12
  • It seems that assignment lines are all extensions to the POSIX syntax, so there cannot be any formal spec for this that covers all implementations ("In the POSIX locale, the user or application shall ensure that a crontab entry is a text file consisting of lines of six fields each." - crontab). Jul 12, 2021 at 12:46

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.