Which files are sourced when using su -c?
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!
Solution 1:
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.