gawk: Id Program

1 
1 11.2.3 Printing Out User Information
1 ------------------------------------
1 
1 The 'id' utility lists a user's real and effective user ID numbers, real
1 and effective group ID numbers, and the user's group set, if any.  'id'
1 only prints the effective user ID and group ID if they are different
1 from the real ones.  If possible, 'id' also supplies the corresponding
1 user and group names.  The output might look like this:
1 
1      $ id
1      -| uid=1000(arnold) gid=1000(arnold) groups=1000(arnold),4(adm),7(lp),27(sudo)
1 
1    This information is part of what is provided by 'gawk''s 'PROCINFO'
1 array (⇒Built-in Variables).  However, the 'id' utility provides
1 a more palatable output than just individual numbers.
1 
1    Here is a simple version of 'id' written in 'awk'.  It uses the user
1 database library functions (⇒Passwd Functions) and the group
DONTPRINTYET 1 database library functions (⇒Group Functions) from *noteLibrary
1DONTPRINTYET 1 database library functions (⇒Group Functions) from ⇒Library

 Functions.
1 
1    The program is fairly straightforward.  All the work is done in the
1 'BEGIN' rule.  The user and group ID numbers are obtained from
1 'PROCINFO'.  The code is repetitive.  The entry in the user database for
1 the real user ID number is split into parts at the ':'.  The name is the
1 first field.  Similar code is used for the effective user ID number and
1 the group numbers:
1 
1      # id.awk --- implement id in awk
1      #
1      # Requires user and group library functions
1      # output is:
1      # uid=12(foo) euid=34(bar) gid=3(baz) \
1      #             egid=5(blat) groups=9(nine),2(two),1(one)
1 
1      BEGIN {
1          uid = PROCINFO["uid"]
1          euid = PROCINFO["euid"]
1          gid = PROCINFO["gid"]
1          egid = PROCINFO["egid"]
1 
1          printf("uid=%d", uid)
1          pw = getpwuid(uid)
1          pr_first_field(pw)
1 
1          if (euid != uid) {
1              printf(" euid=%d", euid)
1              pw = getpwuid(euid)
1              pr_first_field(pw)
1          }
1 
1          printf(" gid=%d", gid)
1          pw = getgrgid(gid)
1          pr_first_field(pw)
1 
1          if (egid != gid) {
1              printf(" egid=%d", egid)
1              pw = getgrgid(egid)
1              pr_first_field(pw)
1          }
1 
1          for (i = 1; ("group" i) in PROCINFO; i++) {
1              if (i == 1)
1                  printf(" groups=")
1              group = PROCINFO["group" i]
1              printf("%d", group)
1              pw = getgrgid(group)
1              pr_first_field(pw)
1              if (("group" (i+1)) in PROCINFO)
1                  printf(",")
1          }
1 
1          print ""
1      }
1 
1      function pr_first_field(str,  a)
1      {
1          if (str != "") {
1              split(str, a, ":")
1              printf("(%s)", a[1])
1          }
1      }
1 
1    The test in the 'for' loop is worth noting.  Any supplementary groups
1 in the 'PROCINFO' array have the indices '"group1"' through '"groupN"'
1 for some N (i.e., the total number of supplementary groups).  However,
1 we don't know in advance how many of these groups there are.
1 
1    This loop works by starting at one, concatenating the value with
1 '"group"', and then using 'in' to see if that value is in the array
1 (⇒Reference to Elements).  Eventually, 'i' is incremented past
1 the last group in the array and the loop exits.
1 
1    The loop is also correct if there are _no_ supplementary groups; then
1 the condition is false the first time it's tested, and the loop body
1 never executes.
1 
1    The 'pr_first_field()' function simply isolates out some code that is
1 used repeatedly, making the whole program shorter and cleaner.  In
1 particular, moving the check for the empty string into this function
1 saves several lines of code.
1