20

I have a cron job that is running a script. When I run the script via an interactive shell (ssh'ed to bash) it works fine. When the script runs by itself via cron it fails.

My guess is that it is using some of the environmental variables set in the interactive shell. I'm going to troubleshoot the script and remove these.

After I make changes, I know I could queue up the script in cron to have it run as it would normally, but is there a way I can run the script from the command line, but tell it to run as it would from cron - i.e. in a non-interactive environment?

4
  • Related and thus possibly helpful: "How to get a clean environment in a ksh shell?" see especially @Gilles answer regarding unset.
    – sr_
    Nov 3, 2011 at 13:16
  • 1
    From @sr_'s link, I looked up env, and you might want to try env -i ./my-script.sh. Also, are you getting an error message?
    – Kevin
    Nov 3, 2011 at 14:12
  • What cron implementation are you using? Nov 3, 2011 at 17:10
  • @kevin - i'll upvote that if you answer with it.
    – cwd
    Dec 20, 2011 at 22:46

7 Answers 7

16

The main differences between running a command from cron and running on the command line are:

  • cron is probably using a different shell (generally /bin/sh);
  • cron is definitely running in a small environment (which ones depends on the cron implementation, so check the cron(8) or crontab(5) man page; generally there's just HOME, perhaps SHELL, perhaps LOGNAME, perhaps USER, and a small PATH);
  • cron treats the % character specially (it is turned into a newline);
  • cron jobs run without a terminal or graphical environment.

The following invocation will run the shell snippet pretty much as if it was invoked from cron. I assume the snippet doesn't contain the characters ' or %.

env - HOME="$HOME" USER="$USER" PATH=/usr/bin:/bin /bin/sh -c 'shell snippet' </dev/null >job.log 2>&1

See also executing a sh script from the cron, which might help solve your problem.

2
  • Hi @Giles - just thought of something - would running a script like sudo -u user /path/to/script also be a way to run it without any variables set?
    – cwd
    Sep 17, 2012 at 19:57
  • @cwd No, usually not. sudo clears some variables and sets others to a known value, but that depends on how it's configured. It is often configured to retain locale settings and TERM, for example. Sep 17, 2012 at 20:00
2

From @sr_'s link (How to get a clean environment in a ksh shell?), I looked up env, and you might want to try this:

env -i ./my-script.sh
2
  • This worked well for me although @Gilles answer is also really good.
    – cwd
    Dec 20, 2011 at 23:29
  • @cwd: Doesn't work for me: echo -e '#!/bin/bash -i\necho interactive $-' > ~/test.sh && chmod +x ~/test.sh && env -i ~/test.sh outputs interactive himB.
    – Alix Axel
    Nov 18, 2012 at 3:14
2

If you'd like to ignore some interactive questions provided by some script, you can try:

yes | your_command

Or yes "n" if you'd like to No all the questions.

Command:

yes -- be repetitively affirmative yes outputs expletive, or, by default, 'y', forever.

2

To run your script in a non-interactive shell (not regarding the details of cron), you can do this via ssh.

Test if you really end up in a non-interactive shell:

> ssh someuser@somehost tty
not a tty

Execute the script in a non-interactive shell:

> ssh someuser@somehost /tmp/myscript.sh
1
  • 1
    This is the only method that created a non-interactive shell
    – joshlk
    Sep 27, 2021 at 16:00
1

I would suggest you use absolute paths for your scripts when putting it in cron and using elsewhere and for any and all linux commands used in it, better declare them as variables and use it thereof!

1
  • yes. but of course.
    – cwd
    Nov 3, 2011 at 15:44
0

Cron doesn't necessarily use the same shell you are using. check:

cat /etc/crontab |grep SHELL

To determine the shell and attempt execution of your script there - does it work? This is a common cause of issues for many people adding scripts to cron.

If this is the problem - you can add "bash" to the beginning of your script in cron to force this script to execute in bash. If this does not solve the issue, let me know and I'll dig a little deeper.

0

The answers here are useful for simulating other details of cron, but if you're specifically looking to simulate non-interactive execution, in most cases you're looking for setsid.

setsid <command> will run <command> independently, with no associated parent process or terminal, very closely simulating an environment where there was never a parent interactive terminal at all.

It won't isolate the command in many others ways though, so if you want to unset environment variables and so on (as in the other answers here) you'll want to simulate that too.

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.