I have an USER
variable in my script, and I want to see his HOME
path based on the USER
variable. How can I do that?
7 Answers
There is a utility which will lookup user information regardless of whether that information is stored in local files such as /etc/passwd
or in LDAP or some other method. It's called getent
.
In order to get user information out of it, you run getent passwd $USER
. You'll get a line back that looks like:
[jenny@sameen ~]$ getent passwd jenny
jenny:*:1001:1001:Jenny Dybedahl:/home/jenny:/usr/local/bin/bash
Now you can simply cut out the home dir from it, e.g. by using cut, like so:
[jenny@sameen ~]$ getent passwd jenny | cut -d: -f6
/home/jenny
-
getent is the better answer, specially with remote user. in simpler systems ~user should be enough. Modded you up. Dec 5, 2015 at 17:55
-
@RuiFRibeiro you can't use
~foo
with variables inbash
. Not directly, anyway.– muruDec 5, 2015 at 18:24 -
1@muru - that's true - and is spec'd behavior. the
~
does seem to tab-expand, though, and another spec'd behavior of the tilde-prefix shall be replaced by a pathname of the initial working directory associated with the login name obtained using thegetpwnam()
function and so probably that lookup is pretty good. i dont like tab-expansions, though - i like to type tabs.– mikeservDec 5, 2015 at 19:27 -
1Note that this only gets you the initial value of $HOME; the user's login scripts are perfectly entitled to change it to something else. This is an unusual thing to do, but I can think of situations where it would be sensible, e.g. choosing between a local and an NFS-mounted homedir.– zwolDec 5, 2015 at 21:57
-
1@HagenvonEitzen Colons are forbidden precisely because they have been used to separate fields.– Jenny DDec 6, 2015 at 13:14
You can use eval
to get someone's home directory.
eval echo "~$USER"
At least for local users this works for sure. I don't know if remote users like LDAP are handled with eval
.
-
1
-
7@nwk an
eval
is needed. Bash doesn't process~foo
after variable expansion.– muruDec 5, 2015 at 18:23 -
1Interesting, thanks, however this only gets the directory of the current user, not of other users. I think LDAP users are not handled, though I can be wrong. Dec 5, 2015 at 18:25
-
3@RuiFRibeiro It will work fine with LDAP, just use whatever variable contains your LDAP user's username instead of
USER
.– muruDec 5, 2015 at 18:34 -
4Don't use this without verifying that
$USER
expands to just a single string of alphabetic characters.– chepnerDec 6, 2015 at 2:43
The usual place is /home/$USER
, but that does not have to be universal.
The definitive place to search for such information is inside the file /etc/passwd
.
That file is world readable (anyone could read it), so any user has access to its contents.
If the $USER exists in the file, the entry previous to last is the user HOME directory.
This will select the entry and print the HOME directory:
awk -v FS=':' -v user="$USER" '($1==user) {print $6}' "/etc/passwd"
For more complex (remote) systems, getent is the usual command to get users information from the NSS (Name Service Switch libraries) system.
A command of
getent passwd "$USER" | cut -d : -f 6
Will provide equivalent information (if available).
-
2you have ~user for that, and your solution does not contemplate users in more complex systems, like user coming from LDAP where you have to use getent. Dec 5, 2015 at 17:57
If the user doesn't exist, getent
will return an error.
Here's a small shell function that doesn't ignore the exit code of getent
:
get_home() {
local result; result="$(getent passwd "$1")" || return
echo $result | cut -d : -f 6
}
Here's a usage example:
da_home="$(get_home missing_user)" || {
echo 'User does NOT exist!'; exit 1
}
# Now do something with $da_home
echo "Home directory is: '$da_home'"
If you are logged in as root, if you know USER
's password, or if the USER
has no password, the following is yet another option:
su -c 'echo ~' ${USER}
Under standard su
behavior, if USER
is undefined or empty, then su
will attempt to run the command as root.
If the value of USER
is not a valid user name, then an appropriate error will be raised: su: user <user> does not exist
.
There are already plenty of good answers here but this may still help someone.
-
This isn't secure, depending on system config. It runs a process (the shell running echo) as that user, so the user could (for example) ptrace the shell and give you arbitrary output. It's also running in the user's setup, so it's possible that the users shell config files are run (which could also give arbitrary outputs). Or environment loads via pam. Etc. Or just do something as simple as send it a SIGSTOP to make it take forever, effectively DOS attacking your script.– derobertApr 16, 2019 at 17:43
getent
is not reliable...
getent
will not work as expected for usernames consisting of all numerics.
Consider username of '0029', getent will return system rpc (in my case, rpc may have a different uid on your system) user details and not username 0029 details.
chown
and a few other system commands will also have issues...
see https://access.redhat.com/solutions/310363
Also see getent man page.
/etc/passwd
is readable by all, so try
'awk -F':' -v U=$USER '$1==U {print $6}' /etc/passwd
-
-
@kikenchitai your link has nothing to do with
chmod
andgetent
, could you check whether it’s actually the link you wanted to use? Jul 28, 2022 at 9:38 -
I'm also getting "access denied" for the Red Hat page. However, I verified -- @kikenchitai is right (at least in RHEL 9). Manpages are obscure but mention only non-numeric keys are passed to
getpwnam(3)
. As an alternative solution, usegetent passwd | grep '^username:'
(from stackoverflow.com/q/35909572/1941654). Either way, we're just getting the passwd database and parsing for the home path. Oct 5 at 23:36
Several reasonable solutions are already posted, but all have issues. For example:
getent passwd "${MY_USER}" | cut -d: -f6
: Will fail for numeric usernames, as pointed out by @kikenchitai.getent passwd "<value>"
assumes UIDs when given numeric values.eval echo "~${MY_USER}"
:eval
is vulnerable to several security concerns. Additionally, this will fail for usernames with spaces or other interpreted characters.awk -v FS=':' -v user="${MY_USER}" '($1==user) {print $6}' "/etc/passwd"
:/etc/passwd
does not provide a complete representation of users, hence the need forgetent
. See read files directly VS getent.Note: See discussion on using
getent passwd
here instead of/etc/passwd
in comments. In short, one critical caveat ofgetent passwd
is that remote users are often not bulk-listable.getent passwd
only lists local users in many cases, whereasgetent passwd <UID>
also queries remote user databases.su -c 'echo ~' "${MY_USER}"
: Requires elevated access, among other security concerns (as mentioned by @derobert).getent passwd | grep "^${MY_USER}:"
: Subject to regex injection. Also subject togetent passwd
only querying the local user database in many cases.
This is the most reliable solution I've seen so far:
getent passwd "$(id -u "${MY_USER}")" | cut -d: -f6
Explanation:
id -u "${MY_USER}"
: Get the user's UID. This should reliably work with local and non-local users (e.g., LDAP users via SSSD).getent passwd "<UID>"
: Get passwd data for the given UID. This will search all user databases via Name Service Switch (not just/etc/passwd
).cut -d: -f6
: Pull the home directory field. This should be consistent across the majority of systems. Most (all?) distributions both assign the sixth field to the home directory and explicitly reserve colons as delimiters without escaping.
-
2
-
2Note too that
getent passwd
isn’t usable everywhere — many directory-based setups prevent listing all the users, in which casegetent passwd
only shows locally-defined users. Oct 9 at 9:36 -
2@muru trivially fixable with the caveat just above (and if that’s fixed by giving the user name on the command line, the caveat mentioned in the first bullet point). Oct 9 at 9:37
-
Thanks for the discussion @muru and @stephen-kitt -- added some commentary to explain this. I see the same behavior on my hosts, where
getent passwd
with no additional parameters only lists local users. Oct 9 at 19:01
$USER
the name of the user that runs the script, or is it an arbitrary username?