[0] https://github.com/coreutils/coreutils/blob/master/src/who.c
[0] https://github.com/coreutils/coreutils/blob/master/src/who.c
I see some comments here citing a lack of options, most of which appear to have nothing to do with who is logged into the machine.
So maybe yes.
* Don't parse the output of ps, unless it is my ps command (or plan 9's one, as here). See https://unix.stackexchange.com/a/593198/5132 and https://unix.stackexchange.com/a/578816/5132 , and their further reading, especially Greg Wooledge's article.
* /proc is as portable as ps, but that doesn't really amount to much because neither is really portable at all. Pretty much every operating system's /proc is different; and no implementation of the ps command fully conforms to even the limited subset laid out in the Single Unix Specification.
sed '/pattern1/d
pattern2/d'
is the same with sed '/pattern1/d; /pattern2/d'
and sed -e '/pattern1/d' -e '/pattern2/d'
I believe those are portable across all `sed` implementations, and they at least work with GNU `sed --posix` and plan9port's sed.http://cvsweb.openbsd.org/src/usr.bin/who/who.c?rev=1.29&con...
this version appears to derive from rewriting unix who in the 4.4BSD era to replace AT&T code (copyright 1989 / no AT&T in header notes as basis for assumption)
it's not quite an apples to apples comparison as his rewrite doesn't handle any options or cleverness, but it's still a massive jump in LOC.
As a concrete example, the linked-to "who" uses:
if (entry.ut_type != USER_PROCESS)
continue;
The GNU one uses: if (IS_USER_PROCESS (utmp_buf))
The IS_USER_PROCESS() macro is in gnulib's readutmp.h (which would need to be included in the overall line cound): # define IS_USER_PROCESS(U) \
(UT_USER (U)[0] \
&& (UT_TYPE_USER_PROCESS (U) \
|| (UT_TYPE_NOT_DEFINED && UT_TIME_MEMBER (U) != 0)))
The UT_USER maps to ut_user on some systems, and ut_name on others: /* Accessor macro for the member named ut_user or ut_name. */
# if HAVE_UTMPX_H
# if HAVE_STRUCT_UTMPX_UT_USER
# define UT_USER(Utmp) ((Utmp)->ut_user)
# endif
# if HAVE_STRUCT_UTMPX_UT_NAME
# undef UT_USER
# define UT_USER(Utmp) ((Utmp)->ut_name)
# endif
This is because, as
https://www.gnu.org/software/libc/manual/html_node/Logging-I... points out, "Note that the ut_user member of struct utmp is called ut_name in BSD. Therefore, ut_name is defined as an alias for ut_user in utmp.h"Each of those other macros supports cases where the machine supports a given test, and when it doesn't. Including for machines which don't implement ut_type! (That's what the UT_TYPE_NOT_DEFINED case is for, which falls back to using the time field ... which has its own set of variants!)
Portability is neither options nor cleverness, so I added it to the list of considerations. But then again, most people now don't need to support decades of history and scores of Unix variants.