92

$ whoami
admin
$ sudo -S -u otheruser whoami
otheruser
$ sudo -S -u otheruser /bin/bash -l -c 'echo $HOME'
/home/admin

Why isn't $HOME being set to /home/otheruser even though bash is invoked as a login shell?

Specifically, /home/otheruser/.bashrc isn't being sourced. Also, /home/otheruser/.profile isn't being sourced. - (/home/otheruser/.bash_profile doesn't exist)

1
  • 1
    A solution to this question will solve the other question as well, you might want to delete the other question in this situation. Jan 2, 2015 at 8:29

3 Answers 3

139

To invoke a login shell using sudo just use -i. When command is not specified you'll get a login shell prompt, otherwise you'll get the output of your command.

Example (login shell):

sudo -i

Example (with a specified user):

sudo -i -u user

Example (with a command):

sudo -i -u user whoami

Example (print user's $HOME):

sudo -i -u user echo \$HOME

Note: The backslash character ensures that the dollar sign reaches the target user's shell and is not interpreted in the calling user's shell.

I have just checked the last example with strace which tells you exactly what's happening. The output bellow shows that the shell is being called with --login and with the specified command, just as in your explicit call to bash, but in addition sudo can do its own work like setting the $HOME.

# strace -f -e process sudo -S -i -u user echo \$HOME
execve("/usr/bin/sudo", ["sudo", "-S", "-i", "-u", "user", "echo", "$HOME"], [/* 42 vars */]) = 0
...
[pid 12270] execve("/bin/bash", ["-bash", "--login", "-c", "echo \\$HOME"], [/* 16 vars */]) = 0
...

I noticed that you are using -S and I don't think it is generally a good technique. If you want to run commands as a different user without performing authentication from the keyboard, you might want to use SSH instead. It works for localhost as well as for other hosts and provides public key authentication that works without any interactive input.

ssh user@localhost echo \$HOME

Note: You don't need any special options with SSH as the SSH server always creates a login shell to be accessed by the SSH client.

3
  • 3
    sudo -i -u user echo \$HOME doesn't work for me. Output: $HOME. strace gives the same output as yours. What's the issue?
    – John_West
    Nov 23, 2015 at 11:12
  • No idea, it still works for me, I'd need to see it or maybe even touch the system. Jan 20, 2016 at 19:02
  • While sudo -i should be a login shell it is different from what sudo su - does on Arch linux. A clear sign the former does not do a login is that it does not display the last login time but that the latter does (and it does a lot more, like have a lot of envvars ready).
    – karatedog
    Oct 21, 2021 at 13:22
13

You're giving Bash too much credit. All "login shell" means to Bash is what files are sourced at startup and shutdown. The $HOME variable doesn't figure into it.

The Bash docs explain some more what login shell means: https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html#Bash-Startup-Files

In fact, Bash doesn't do anything to set $HOME at all. $HOME is set by whatever invokes the shell (login, ssh, etc.), and the shell inherits it. Whatever started your shell as admin set $HOME and then exec-ed bash, sudo by design doesn't alter the environment unless asked or configured to do so, so bash as otheruser inherited it from your shell.

If you want sudo to handle more of the environment in the way you're expecting, look at the -i switch for sudo. Try:

sudo -S -u otheruser -i /bin/bash -l -c 'echo $HOME'

The man page for sudo describes it in more detail, though not really well, I think: http://linux.die.net/man/8/sudo

4
  • 4
    $HOME isn't set by bash - Thanks, I didn't know that.
    – user80551
    Jan 2, 2015 at 8:11
  • Look for strace in my answer. It shows that you don't need to build /bin/bash -l -c 'echo $HOME' command line yourself when using -i. Jan 2, 2015 at 9:46
  • 1
    That sudo syntax threw an error on my machine. (su uses the -c option, but I don't think sudo does.) I had better luck with: HomeDir=$( sudo -u "$1" -H -s echo "\$HOME" )
    – palswim
    Oct 13, 2016 at 20:21
  • yeah, @palswim is right. Not sure about -S (I didn't need it, so I left it out), but -c doesn't work here, you need -s instead. Jan 7, 2019 at 23:34
0
sudo -u www-data bash -i -c "env"

Notice the -i flag, telling bash to run interactively.

This command will execute an interactive bash shell for user www-data, within which shell (as an example) the env command is executed.

This works even if user www-data has a nologin shell as their default shell.

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.