60

I have set my environment variable using /etc/profile:

export VAR=/home/userhome

Then if I do echo $VAR it shows /home/userhome

But when I put reference to this variable into the /etc/init.d/servicename file, it cannot find this variable. When I run service servicename status using /etc/init.d/servicename file with following content:

case "$1" in
status)    
    cd $VAR/dir
    ;;
esac

it says /dir: No such file or directory

But it works if I run /etc/init.d/servicename status instead of service servicename status

How can I make unix service see environment variables?

altern
  • 1,980
  • Note that invoking the System 5 rc script directly also does not operate that way on systemd operating systems, as all invocations of the script are turned into invocations of systemctl by a hidden hook. – JdeBP Jan 08 '17 at 10:51

3 Answers3

82

The problem is service strips all environment variables but TERM, PATH and LANG which is a good thing. If you are executing the script directly nothing removes the environment variables so everything works.

You don't want to rely on external environment variables because at startup the environment variable probably isn't present and your init system probably won't set it anyway.

If you still want to rely on such variables, source a file and read the variables from it, e.g. create /etc/default/servicename with the content:

VAR=value

and source it from your init script, e.g:

[ -f /etc/default/service-name ] && . /etc/default/service-name

if [ -z "$VAR" ] ;  then
  echo "VAR is not set, please set it in /etc/default/service-name" >&2
  exit 1
fi

case "$1" in
status)    
    cd "$VAR"/dir
    ;;
esac
Ulrich Dangel
  • 25,369
  • 18
    Very helpful, thanks. For other Linux newbies, here's the cryptic Bash stuff. [ ... ] is a shorthand for a conditional test; see this answer. -f is an if argument to check if file exists. && is a short-circuit operator: only do the second command if the first exits with 0. . source or dot operator: read and execute commands from the filename argument. -z is an if argument to check for a zero-length string. >&2 send output to stderr. See also Introduction to if. – Mark Berry Jun 12 '14 at 20:06
  • @MarkBerry -f is part of [, not if. – Chris Down Mar 26 '15 at 16:00
  • @ChrisDown, thanks. So "[ ... ] is a shorthand for a conditional test command; see this answer. -f is a test argument to check if a file exists." – Mark Berry Mar 26 '15 at 23:17
  • @MarkBerry Correct. You can think of [ (or test) as just another command -- all if does is take some action based on exit status. – Chris Down Mar 26 '15 at 23:19
  • I've run into a situation similar to this, but I don't need $VAR to be in the init script, I need it to be available to a different program 2 or 3 calls downstream of the init script. Eg. init script calls start-stop-daemon which calls Program 1 (Java) which calls Program 2 which needs $VAR. I tried the trick in this answer but it doesn't seem to work in my situation. How can I ensure that $VAR will be available to Program 2? – FrustratedWithFormsDesigner Aug 07 '15 at 19:23
  • Sorry but, are you sure that this example really works? I have seen comments in other post like "a child process cannot change environment variables" and I have tested something like this example, and it didn't worked. – ivanleoncz May 16 '17 at 20:09
3

In my case, I needed a RAILS_ENV that was set in /etc/bash.bashrc: export RAILS_ENV=staging. I added $(grep RAILS_ENV /etc/bash.bashrc) and that made the variable available to the script. I did it this way so i didn't have to include the rest of the file.

HalosGhost
  • 4,790
geermc4
  • 131
1

One ugly solution that will also work:

function exec() {
    args=( $@ )
    command=${args[0]}
    dummy=${args[1]}
    whoami=`whoami`
    if [ -z "$dummy" ]; then
        me=`basename $0`
        runuser -l ${whoami} -c "bash /etc/init.d/${me} ${command} dummy"
    else
       printenv
   fi
}

case $1 in
    status)
        status
        ;;
    start|stop|kill|restart)
        exec $*
        ;;
    *)
        usage
esac
Maksim
  • 119