62

Also, will these variables always match currently logged-in username (they do on my Debian system)? Can I assume their availability in other Unix(-like) systems?

I'm also curious why one would use whoami instead of just reading any of these variables.

5
  • 3
    Looking at the man page, whoami reports the name associated with your effective user ID. Which means it will return something different if you're using sudo or running a setuid executable. If you have sudo set up, try sudo whoami for example.
    – Joseph R.
    Commented May 19, 2013 at 11:44
  • 7
    USER and USERNAME are ordinary environment variables, which means that, if you want, you can set them to arbitrary values. Just type USER=xyz. In other words, even if those variables exist, there is no guarantee that their values match the currently logged-in username.
    – Uwe
    Commented May 19, 2013 at 12:03
  • @Uwe By guarantee, I meant by default (i.e. assuming user did not change them).
    – tshepang
    Commented May 19, 2013 at 12:22
  • 2
    @Tshepang As a follow up to my first comment: compare the results of sudo whoami and sudo echo $USER
    – Joseph R.
    Commented May 19, 2013 at 16:58
  • 2
    @JosephR. For sudo echo $USER, the shell expands $USER, then calls sudo. So of course it doesn't produce the same output as whoami. Like sudo whoami, sudo sh -c 'echo $USER' does (typically) output root. Regarding your comment about whoami using the EUID, note that sudo whoami would output root even if whoami used the UID. sudo sets both EUID and UID for the command it runs (except in the very unusual situation that you explicitly configure it to behave otherwise). Compare sudo id -u to sudo id -ru. Commented Oct 7, 2014 at 16:55

4 Answers 4

46

It's login.

The Linux login(1) man page says:

The value for $HOME, $USER, $SHELL, $PATH, $LOGNAME, and $MAIL are set according to the appropriate fields in the password entry.

The FreeBSD login(1) man page says:

The login utility enters information into the environment (see environ(7)) specifying the user's home directory (HOME), command interpreter (SHELL), search path (PATH), terminal type (TERM) and user name (both LOGNAME and USER).

The NetBSD, OpenBSD and OS X man pages say the same thing.

Here's the source code from the util-linux login:

setenv("HOME", pwd->pw_dir, 0); /* legal to override */
setenv("USER", pwd->pw_name, 1);
setenv("SHELL", pwd->pw_shell, 1);
/* ... */
setenv("LOGNAME", pwd->pw_name, 1);

Here's the source code from the FreeBSD login:

(void)setenv("LOGNAME", username, 1);
(void)setenv("USER", username, 1);
(void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
7
  • 3
    On my Fedora 16 box, I have both USER and USERNAME set and your command only returns LOGNAME.
    – Joseph R.
    Commented May 19, 2013 at 11:50
  • 1
    @JosephR., unfortunately I don't have Fedora on hands but I've looked into FreeBSD's sources as well, see UPD..
    – poige
    Commented May 19, 2013 at 12:43
  • 1
    But this is obviously not the case on Fedora. All I'm saying is, login doesn't seem to be the only thing setting these variables.
    – Joseph R.
    Commented May 19, 2013 at 14:10
  • 4
    Note that Linux is just a kernel, it doesn't have a login command. OSes that use Linux as their kernel are free to use any implementation they like. For instance, Debian based systems tend to use the one from shadow-utils, not util-linux. Commented Jan 7, 2017 at 9:34
  • 2
    Note that login is often not invoked when logging in over ssh or by most graphical login managers. Commented Jan 7, 2017 at 9:35
17

There's no rule. Some shells like tcsh or zsh set $LOGNAME. zsh sets $USERNAME (you can even assign a value to the variable to change uids/gids to those of that user there if permitted to).

It may be set by some things that log you in like login (as invoked by getty when login on a terminal and sometimes by other things like in.rlogind), cron, su, sudo, sshd, rshd, graphical login managers or may not.

If there's been a login though, in my experience, $USER is generally set (but it may not be updated after a change of user id (via setuid commands) within that login session. POSIX requires that $LOGNAME be set upon login (and cron).

To get the login name portably, best is to use the logname command (if there's not been any login, it may return nothing). To get the user id, use id -u. To get one username corresponding to the current effective user id: id -un. To get all of them (most of the time, there's only one user name per user id, but that's not guaranteed):

perl -le 'while ($n = getpwent()) {print $n if getpwnam($n) == $>}'

Though that may not work on systems where the user database cannot be enumerated (as happens sometimes with networked user databases for instance).

9

You probably want to rely on the POSIX standard here, since at some point in time you will probably care about not just user login (managed by the login program) but also cron jobs and the like.

Therefore, you should know that POSIX requires $LOGNAME but not $USER. E.g. $USER may not be set by cron, as pointed out in an answer by Keith Thompson, which also references some history on how this relates to the history of System-V vs BSD:

... at least on my system (Ubuntu 14.04) the $USER environment variable is not set for cron jobs. Instead, you can use $LOGNAME, which is part of the environment for cron jobs.

According to the environ(7) man page (type man environ to read it), $USER is used by BSD-derived programs and $LOGNAME is used by System-V-derived programs.

5

If you want to use the environment variables (instead of whoami or getpwent and getpwnam) and you are unsure if they are always set the same way on all *NIX systems, then try this in bash:

THIS_USER=${USER:-${USERNAME:-${LOGNAME}}}
echo ${THIS_USER}

If it is still empty after all that, then you are on a rather esoteric system. ;)

4
  • All of these 3 variables are unset in a Docker container running centos:7 and Host network. Commented Feb 26, 2021 at 23:09
  • Interesting. My centos7 docker image sets USER. It would seem that your centos7 image never simulates running login to set those up. Hmm. Commented Feb 28, 2021 at 2:04
  • 1
    The Dockerfile does this: ENV user=foo USER ${user} WORKDIR /home/${user} It works fine: "The USER instruction sets the user name (or UID) and optionally the user group (or GID) to use when running the image and for any RUN, CMD and ENTRYPOINT instructions that follow it in the Dockerfile." Commented Feb 28, 2021 at 15:28
  • 1
    If I want to use USER inside ENTRYPOINT, I can modify Dockerfile, I guess, to do ENV USER=foo. Just something to keep in mind... Commented Feb 28, 2021 at 15:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .