Ubuntu – Which files are sourced when using su -c

bashbashrccommand linerootsu

Context

You are working on Ubuntu LTS 14.04. You are logged in as the root user.
You run the following command:

exec su simple_user -c "/bin/bash /etc/init.d/simple_user_service"

So that the "simple_user_service" is launched with "simple_user" privileges and not root privileges.

Question

It seems that "exec su simple_user -c" doesn't source .bashrc nor .profile nor any other normally sourced file for new interactive shell terminal. I confirmed that by adding this line in simple_user .bashrc file:

export TEST="Hello"

Then in my "simple_user_service" init script:

#!/bin/bash
### BEGIN INIT INFO
# Provides:             test_script
# X-Interactive:        true
# Short-Description:    Test script
### END INIT INFO

echo $TEST

When I execute the script, nothing is printed, but if I execute the following commands:

su simple_user
echo $TEST
> Hello

The TEST variable is set and printed out correctly.

So I was wondering: does "exec su simple_user -c" command source any simple_user profile/bashrc files? If so, is there a way to know which ones?

Thanks a lot for your help!

[Edit – 2 hours later]

Thanks to the answer I received, I understood more accurately 'man bash' instructions. I found this:

   When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it  appears  there,  and
   uses the expanded value as the name of a file to read and execute.  Bash behaves as if the following command were executed:
          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
   but the value of the PATH variable is not used to search for the file name.

It is really interesting as you can set BASH_ENV to a file that runs specific commands each time you use "su simple_user -c" without requiring to load the full interactive logic.

So, before executing su simple_user -c, you can simply do:

export BASH_ENV=~/.bash_script

And set things in your simple_user .bash_script file, like:

export TEST="Hello"

Then when I execute the "simple_user_service" script, "Hello" is properly printed.

It was really usefull for me as I needed this to load all the "rvm" environment (ruby) to run a specific script.

Want to know more?

Why all this trouble?

Because I installed ruby god: http://godrb.com/ to monitore this specific script (a delayed job one).

And I'm using "rvm" to manage different rubies.

And the script automatically drop privileges if necessary by executing exec su application_user -c "/bin/bash application_script"

As god needs to run with root privileges and rvm is only loaded in .bashrc/.profile files, I needed a way to properly load rvm environment in my script. I could simply add the rvm load command in the script, but then my script would have been environment dependant and that was not acceptable.

So I added this in my script before privileges are dropped:

if [ -e "config/BASH_ENV" ]; then
  export BASH_ENV=$(cat config/BASH_ENV)
fi

Thanks to that I can load rvm in the file I set in the config/BASH_ENV file. For instance it could be:

# In config/BASH_ENV file of your rails app:
export BASH_ENV="~/.bash_script"

# In /home/simple_user/.bash_script 
[[ -s "/etc/profile.d/rvm.sh" ]] && . "/etc/profile.d/rvm.sh" # Load RVM function

Then, my script and god work as expected.

I did not explain all those things before getting answers so that readers could focus on the real question.

But as I got a good answer and found a good solution thanks to that, I wrote this edit so that it may be useful to others.

Thanks again!

Best Answer

When you do:

su some_user -c 'some_command'    

The some_command will be executed as:

bash -c 'some_command'

Assuming bash is some_user's shell defined in /etc/passwd.

Now when you do bash -c 'some_command' you are basically spawning a non-interactive (and of course non-login) session of bash. As no file is sourced by the shell while in non-interactive mode so no file is being read expectedly.

Note that ~/.profile is sourced in a login, interactive session of bash and ~/.bashrc is sourced in a non-login, interactive session of bash. Also note that Ubuntu sources ~/.bashrc from ~/.profile.

Check the INVOCATION section of man bash to get more idea.