Update: Based on this question's title, people seem to come here just looking for a way to find a different user's home directory, without the need to impersonate that user.
In that case, the simplest solution is to use tilde expansion with the username of interest, combined with eval
(which is needed, because the username must be given as an unquoted literal in order for tilde expansion to work):
eval echo "~$different_user" # prints $different_user's home dir.
Note: The usual caveats regarding the use of eval
apply; in this case, the assumption is that you control the value of $different_user
and know it to be a mere username.
By contrast, the remainder of this answer deals with impersonating a user and performing operations in that user's home directory.
Note:
- Administrators by default and other users if authorized via the
sudoers
file can impersonate other users via sudo
.
- The following is based on the default configuration of
sudo
- changing its configuration can make it behave differently - see man sudoers
.
The basic form of executing a command as another user is:
sudo -H -u someUser someExe [arg1 ...]
# Example:
sudo -H -u root env # print the root user's environment
Note:
- If you neglect to specify
-H
, the impersonating process (the process invoked in the context of the specified user) will report the original user's home directory in $HOME
.
- The impersonating process will have the same working directory as the invoking process.
- The impersonating process performs no shell expansions on string literals passed as arguments, since no shell is involved in the impersonating process (unless
someExe
happens to be a shell) - expansions by the invoking shell - prior to passing to the impersonating process - can obviously still occur.
Optionally, you can have an impersonating process run as or via a(n impersonating) shell, by prefixing someExe
either with -i
or -s
- not specifying someExe ...
creates an interactive shell:
Using a shell means that string arguments passed on the command line MAY be subject to shell expansions - see platform-specific differences below - by the impersonating shell (possibly after initial expansion by the invoking shell); compare the following two commands (which use single quotes to prevent premature expansion by the invoking shell):
# Run root's shell profile, change to root's home dir.
sudo -u root -i eval 'echo $SHELL - $USER - $HOME - $PWD'
# Don't run root's shell profile, use current working dir.
# Note the required -H to define $HOME as root`s home dir.
sudo -u root -H -s eval 'echo $SHELL - $USER - $HOME - $PWD'
What shell is invoked is determined by "the SHELL environment variable if it is set or the shell as specified in passwd(5)" (according to man sudo
). Note that with -s
it is the invoking user's environment that matters, whereas with -i
it is the impersonated user's.
Note that there are platform differences regarding shell-related behavior (with -i
or -s
):
sudo
on Linux apparently only accepts an executable or builtin name as the first argument following -s
/-i
, whereas OSX allows passing an entire shell command line; e.g., OSX accepts sudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD'
directly (no need for eval
), whereas Linux doesn't (as of sudo 1.8.95p
).
Older versions of sudo
on Linux do NOT apply shell expansions to arguments passed to a shell; for instance, with sudo 1.8.3p1
(e.g., Ubuntu 12.04), sudo -u root -H -s echo '$HOME'
simply echoes the string literal "$HOME" instead of expanding the variable reference in the context of the root user. As of at least sudo 1.8.9p5
(e.g., Ubuntu 14.04) this has been fixed. Therefore, to ensure expansion on Linux even with older sudo
versions, pass the the entire command as a single argument to eval
; e.g.: sudo -u root -H -s eval 'echo $HOME'
. (Although not necessary on OSX, this will work there, too.)
The root
user's $SHELL
variable contains /bin/sh
on OSX 10.9, whereas it is /bin/bash
on Ubuntu 12.04.
Whether the impersonating process involves a shell or not, its environment will have the following variables set, reflecting the invoking user and command: SUDO_COMMAND
, SUDO_USER
, SUDO_UID=
, SUDO_GID
.
See man sudo
and man sudoers
for many more subtleties.
Tip of the hat to @DavidW and @Andrew for inspiration.