As far as I know, all unix variants have an /etc/passwd
file with the traditional layout, for the sake of applications that read the file directly. Each line in the file contains colon-separated records which correspond to struct passwd
fields:
- user name (login)
- encrypted password (if present)
- user id (number, in decimal)
- principal group id (number, in decimal)
- Gecos field. This field is not used by system programs except for display purposes. It is normally a comma-separated list of fields, the first three being full name, office number and telephone number.
- home directory
- login shell
One thing that varies between systems is how much liberty you can take with the syntax. For example, GNU libc (i.e. Linux) ignores lines that begin with #
: they are comments. GNU libc also ignores whitespace at the beginning of a line, so they can be indented. An invalid line might cause programs to stop processing the file or to skip to the next line.
Most modern systems no longer store an encrypted password in the second field. The content of that field is not a reliable indication of whether the user has a password set (and even if you found that out, this is not a reliable indication of whether the user can log in, because there are many other authentication methods such as SSH keys, one-time passwords, biometrics, smartcards, …).
When passwords aren't in /etc/passwd
, where they are is system-dependent. The Rosetta Stone for Unix mentions many unix variants.
- Solaris uses
/etc/shadow
, and this has been copied by others including Linux. Linux and Solaris shadow files have the same format; I don't know if the other systems that have a file called /etc/shadow
use the same format.
- BSD systems have
/etc/master.passwd
, and additionally have database files for faster access, updated by pwd_mkdb
.
Remember that /etc/passwd
hasn't been guaranteed to contain the full list of users for a couple of decades: users can come from other databases such as NIS (YP) or LDAP. As a system administrator, avoid edit the /etc/passwd
file directly; use vipw
instead, if your system provides it (and if it doesn't, consult your manuals to see what method is recommended to modify the user database).
What I wrote above goes for groups, too. The fields in /etc/group
are struct group
members: group name, password (largely unused), numerical group id, and a comma-separated list of user names (the users who have this group as a secondary group). Linux has a /etc/gshadow
file, but this is rarely used, as group authentication is not widely practiced.
Here's an extension of the_velour_fog's answer, adapted to use second/minute/day/month/year.
#!/usr/bin/env bash
last_run="2018-06-21T21:10:18-06:00"
function rel_fmt_low_precision() {
local SEC_PER_MINUTE=$((60))
local SEC_PER_HOUR=$((60*60))
local SEC_PER_DAY=$((60*60*24))
local SEC_PER_MONTH=$((60*60*24*30))
local SEC_PER_YEAR=$((60*60*24*365))
local last_unix="$(date --date="$1" +%s)" # convert date to unix timestamp
local now_unix="$(date +'%s')"
local delta_s=$(( now_unix - last_unix ))
if (( delta_s < SEC_PER_MINUTE * 2))
then
echo "last run "$((delta_s))" seconds ago"
return
elif (( delta_s < SEC_PER_HOUR * 2))
then
echo "last run "$((delta_s / SEC_PER_MINUTE))" minutes ago"
return
elif (( delta_s < SEC_PER_DAY * 2))
then
echo "last run "$((delta_s / SEC_PER_HOUR))" hours ago"
return
elif (( delta_s < SEC_PER_MONTH * 2))
then
echo "last run "$((delta_s / SEC_PER_DAY))" days ago"
return
elif (( delta_s < SEC_PER_YEAR * 2))
then
echo "last run "$((delta_s / SEC_PER_MONTH))" months ago"
return
else
echo "last run "$((delta_s / SEC_PER_YEAR))" years ago"
return
fi
}
rel_fmt_low_precision "`date`"
rel_fmt_low_precision "2018-06-21 21:10:18"
rel_fmt_low_precision "2018-06-21 20:10:18"
rel_fmt_low_precision "2018-05-21 21:10:18"
rel_fmt_low_precision "2017-06-21 20:10:18"
rel_fmt_low_precision "2016-06-21 20:10:18"
Here's how it decides which unit to use: it uses the largest unit that gives a number of at least two.
Example: If something happened 72 hours ago, it will output in days. If something happened exactly an hour ago, it will use minutes.
Best Answer
Example Output: