I am using Ubuntu 8.04 Linux. I have a cron job entry to run a shell script at a scheduled time. This script has a X application to be launched. As cron does not pick already exported environment variables and it runs in a separate environment, I need to export the DISPLAY variable to run my GUI process. So I am setting the DISPLAY environment variable through command substitution at the top of my script as follows:
export DISPLAY="`who am i | cut -d"(" -f2 | cut -d")" -f1`"
It seems, this does not work with cron (i.e) cron is not executing command substitution inside shell script or at the crontab's "command field" entry (i.e):
a) Why cron does not support "command substitution"?
b) Also, I have exported DISPLAY in my .bashrc file (since my login shell is bash) and I have specified this shell at the top of the crontab as: SHELL=/bin/bash. Still why cron is not reading it from ~/.bashrc while executing my script??
c) Since cron is not associated to any terminal (/dev/tty) I guess no need for trapping HUP signal?
First off - ALL comands in a cron entry or in a cron script should have explicit paths to command files. The PATH is not the same as you have at the command line.
who am i can be implemented all kinds of ways, as an alias or some other feature of the who command. It is usually this:
/usr/bin/who am i
where "am and "i" are arguments.
You need to experiment with each simple element of your command in crontab entry - enter the command let it run, remove it from crontab, then check the log or email.
example
* * * * * /usr/bin/who am i >> /home/royalibrahim/logfile
wait a minute, remove the crontab entry and then read the logfile. Proceed iteratively.
Is there some reason not to use the shell variable $USER?
cron never supported command substitution. It can only "support" it as far as the used shell (/bin/sh) supports it.
cron doesn't care for you .bashrc, or any other login file for that matter, because it won't start a login shell. What it will do is basically text /bin/sh -c "your command"
at the specified time. As an example, this is the environment of a command started by cron on Linux: text SHELL=/bin/sh USER=pludi PATH=/usr/bin:/bin PWD=/home/pludi SHLVL=1 HOME=/home/pludi LOGNAME=pludi _=/usr/bin/env
See the minimal path? That's all you have at the start of your script.
If you want to start an XTerm on a remote display for a certain user, you'll need to know where to connect to. But that's an information that cron couldn't possibly find out, as it will run even if you aren't connected. It will even run on Sundays, when (probably) no one is in the office. Where should the terminal be shown at then?
What if I am running only on my local machine (i.e) launching the xterm terminal in my local system - not on the remote systems?
So, command substitution is not possible in whatever be the case, right? what if scripts that are need to be run by cron, have the need of command substitution? How to achieve this? Is this a deficiency in cron - is that incapable to do that?
cron doesn't care whether you're connected locally or from somewhere else, because it's primary design goal since it's creation was to run programs without any user interaction. That means no TTYs, no X displays by default, so it has no way of knowing what display you're running an X server at. You'll have to tell it that yourself, by whatever means (eg. writing the required DISPLAY variable to a file & reading that in your script)
As for substitution: no, cron doesn't know anything about that, because the shell can handle it just fine. The whole command you specify is passed, without any interpolation, to a shell, which then has to handle parameter & command expansion. Example: the line
To find out the environment variables which are set when a job starts in the default shell for cron, create a one-off cron containing just an "env" command. The output from "env" will be in the mail for the user who owns the cron.
We're still not clear what you are trying to achieve but using "cron" (which is a background task scheduler) to try to start a process which needs a foreground terminal is unlikely to be satisfactory.
Then my cron_env.sh sets up my full required environment,
and runs my script exactly in an environment I control completely, and not at the whims of however cron kicks things off.