It is late, a restart is waiting, and someone asks the deceptively simple question: “Is anybody still on this machine?” This is exactly when who is useful—and exactly when a tidy line of terminal output can inspire more confidence than it deserves.

who reports session records maintained by the operating system. It can show a login name, terminal, login time, and sometimes a remote origin. It cannot promise that every record is fresh, that every active process belongs to an interactive login, or that every container and service wrote a record at all.

Meet the people the login database remembers

Terminalbash
who
<user>   seat0        2026-09-03 11:10 (login screen)
<user>   tty2         2026-09-03 11:10 (tty2)

Read each column as evidence, not a verdict

  • The first field is the login name recorded for the session.

  • seat0, tty2, or a value such as pts/3 identifies the associated line or terminal. A pts entry is commonly a pseudoterminal created by SSH, a terminal emulator, or another program.

  • The timestamp is when that session record says the login began, not the time of the user’s most recent command.

  • A parenthesized value is the host or comment field. It may contain a remote hostname, an address, or a local display comment such as login screen; its presence and meaning depend on the login path.

  • This is sanitized output reproduced locally with GNU Coreutils 9.4. The real username was replaced with <user>; the two-record shape, terminal names, timestamps, and comments were preserved.

Where the answer comes from

On a conventional Linux host, current sessions are represented by the utmp database, commonly exposed at /run/utmp or the historical path /var/run/utmp. The exact pathname and implementation are system-dependent. Login-aware programs create and update records; the kernel does not magically infer a perfect list of human activity.

  • who normally reads the current-session file selected by the platform or C library.

  • /var/log/wtmp commonly stores historical login, logout, boot, and related records. It is the usual data source for last, not a plain-text log to open in an editor.

  • A program that never writes utmp records will be invisible to who. Containers, minimal systems, terminal multiplexers, display managers, and unusual SSH or PAM configurations can produce surprising results.

  • A crashed session or imperfect cleanup can leave stale records. Conversely, an active process may exist without an interactive-login record.

  • Treat remote host text as operational context, not authenticated identity by itself. Hostnames can be absent, truncated, resolved differently, or privacy-sensitive.

Add headings and idle context during an incident

Terminalbash
who -uH
NAME     LINE         TIME             IDLE          PID COMMENT
<user>   seat0        2026-09-03 11:10   ?          3010 (login screen)
<user>   tty2         2026-09-03 11:10  old         3010 (tty2)

Idle is helpful context, never permission

  • -H adds headings. It changes presentation, not the underlying records.

  • With GNU who, -u adds idle time and the process ID associated with the session.

  • A dot in the idle column means activity within the last minute; old means more than 24 hours. A clock-like value represents hours and minutes.

  • A question mark means the idle state could not be determined. It does not mean that the user is definitely idle.

  • Background computation, an editor left open, or a long-running command may matter even when keyboard activity is old. This sanitized result was executed locally with GNU Coreutils 9.4.

Count names without pretending they are people

Terminalbash
who -q
<user> <user>
# users=2

Two records may still belong to one human

  • GNU -q or --count prints the login name from each current record and then the number of records.

  • One account may have several terminals, so this is a session-oriented count—not a count of unique humans.

  • The same name appeared twice in the local probe because the host recorded both seat0 and tty2.

  • The names above are sanitized; the count of two was executed locally with GNU Coreutils 9.4.

  • If the business question is “how many licensed users?” or “who is an employee?”, the login database is the wrong source.

Ask when Linux booted and which run level was recorded

Terminalbash
who -b
who -r
         system boot  2026-09-03 11:10
         run-level 5  2026-09-03 11:10

These are special records, not logged-in users

  • GNU -b selects the time of the last recorded system boot.

  • GNU -r displays the recorded current run level. On a systemd machine, traditional run levels are compatibility concepts mapped to targets.

  • The timestamps shown were returned locally by GNU Coreutils 9.4.

  • Compare with uptime -s, systemctl get-default, or the system journal when investigating boot behavior; different tools can answer subtly different questions.

  • A missing record may reflect the host’s logging environment rather than evidence that the event never happened.

Let the all-options view expose the odd records

Terminalbash
who -a
           system boot  2026-09-03 11:10
           run-level 5  2026-09-03 11:10
<user>   ? seat0        2026-09-03 11:10   ?          3010 (login screen)
<user>   + tty2         2026-09-03 11:10  old         3010 (tty2)
           pts/7        2026-09-03 20:57             32068 id=ts/7  term=0 exit=1

The symbols and dead sessions need translation

  • For GNU Coreutils, -a combines several selectors, including boot time, dead processes, login processes, run level, current users, init-spawned processes, headings, and idle information.

  • With message status enabled by that aggregate view, + means the terminal is writable, - means it is not, and ? means the terminal line could not be found.

  • term= and exit= belong to dead-process records and describe termination and exit status fields; they are not another logged-in user.

  • This sanitized excerpt came from the local GNU Coreutils 9.4 probe. Two dead pseudoterminal records were present; the display was shortened only to keep the example readable.

  • -a is excellent for diagnosis but noisy for dashboards and fragile for parsing. Select the record type you actually need.

Check whether a terminal accepts messages

Terminalbash
who -T
<user>   ? seat0        2026-09-03 11:10 (login screen)
<user>   + tty2         2026-09-03 11:10 (tty2)

A plus sign is narrower than availability

  • GNU -T, -w, and --mesg request the same message-status field.

  • + indicates that another user may write to that terminal according to its permissions; it does not prove anyone is watching it.

  • - means messages are disallowed and ? means the terminal device could not be resolved.

  • The output was executed locally and the account name sanitized.

  • Use mesg y or mesg n only on your own controlling terminal and within local communication policy.

The strange little phrase who am i

Terminalbash
who am i
(no output)

Silence can be the correct result

  • The historical two-argument form who am i is equivalent to GNU who -m: it attempts to show only the entry associated with standard input.

  • The words am and i are not independently interpreted as English; compatibility rules recognize two non-option arguments.

  • It is not the same as whoami, which reports the effective user name of the current process.

  • In the local automation environment, who am i returned no record because the process did not have a matching controlling-terminal session. That empty result was observed with GNU Coreutils 9.4.

  • Cron jobs, CI runners, containers, redirected standard input, sudo, SSH command mode, and terminal multiplexers can all make “the current login” more complicated than it sounds.

Choose the command that matches the human question

  • who: current records, terminals, login times, and optional record details.

  • whoami: the effective user name of the process running the command.

  • id: real/effective identity and group information; usually the better choice for permissions diagnosis.

  • w: session records plus activity and load-oriented context. Command fields may reveal sensitive information.

  • users: a compact list of login names from current records, with repeated names for multiple sessions.

  • last: historical sessions and boots read from wtmp-style records.

  • loginctl list-sessions: systemd-logind’s session model, which can be more appropriate on systemd hosts and exposes machine-readable properties through loginctl show-session.

Keep human output out of brittle automation

who output was designed for an operator looking at a terminal. Whitespace separates fields, but the comment can contain spaces; dates and headings can vary with locale and implementation; host information may be missing; and terminals can come and go between reading and acting.

  • Do not split a default line on whitespace and assume the fourth token is always a host.

  • Set a known locale only when a script explicitly depends on a documented format, and still test the exact implementation deployed.

  • For systemd session automation, prefer loginctl show-session properties over scraping the aligned table from loginctl list-sessions.

  • For security auditing, use the journal, audit subsystem, centralized identity data, or another authoritative event source with retention and tamper controls.

  • Never publish raw who, w, or last output casually: user names, remote origins, working activity, and login patterns can be sensitive.

  • POSIX specifies a smaller who interface, including the two-argument terminal form. Options such as GNU -q, -b, -r, -u, -T, and the exact -a aggregation must be labeled and tested as implementation-specific.

When the machine disagrees with your expectation

  • An SSH user is missing: check whether the connection allocated a pseudoterminal and whether that login path updates utmp; a noninteractive SSH command may have no session record.

  • A departed user remains: suspect stale utmp state, then corroborate with processes, terminal devices, login management, and logs instead of deleting database files.

  • The same name appears twice: inspect the terminal column; one account can own multiple simultaneous records.

  • `who am i` prints nothing: the process may have no matching standard-input terminal or the terminal may lack an utmp record.

  • The host field is blank: local sessions and some login paths do not supply one.

  • Idle shows `?`: the terminal device or access time could not be inspected; do not convert uncertainty into “inactive.”

  • Container output is empty: many images have no conventional utmp lifecycle. Inspect the container runtime and processes for the operational question at hand.

  • A script broke on another Unix: return to the POSIX subset or detect and test the target implementation rather than assuming GNU extensions.

The reassuring thing about who is how quickly it gives a roomful of terminals names and times. The responsible thing is remembering what is outside that room: batch work, services, containers, stale entries, and people whose session record says nothing about the importance of what they started.

Use it to begin the conversation with the machine. Before a disruptive decision, finish the conversation with the workload and the humans responsible for it.

Keep exploring Linux from the terminal

References used to verify the details