bballdave025
bballdave025

Reputation: 1428

Output groups one per line, with group name and group ID

Here is the information about the groups to which I belong, from the id command. I've made it so the output would be easier to read. I'm including this output "exactly" as it came back from the command line. (Thanks @EdMorton.)

$id
uid=1(me) gid=545(Users) groups=545(Users),66049(CONSOLE LOGON),11(Authenticated Users),4095(CurrentSession),66048(LOCAL)

Here is the output I want, comma delimited, with one group name and its GID per line:

$ some-great-command
'Users',545
'CONSOLE LOGON',66049
'Authenticated Users',11
'CurrentSession',4095
'LOCAL',66048

I came up with a horrendous way to do this:

$ id | sed 's/\(.*groups=\)\(.*$\)/\2/' | awk -F "," '{ for(i = 1; i <= NF; i++) print $i;}' | sed 's/\(^[[:digit:]]\+\)[(]\([A-Za-z +_]\+\)[)]$/'"'"'\2'"'"',\1/'

(I'll put it here again with a little nicer on-screen format, using \)

$ id | sed 's/\(.*groups=\)\(.*$\)/\2/' | \
awk -F "," '{ for(i = 1; i <= NF; i++) print $i;}' | \
sed 's/\(^[[:digit:]]\+\)[(]\([A-Za-z +_]\+\)[)]$/'"'"'\2'"'"',\1/'

but I can't help but think there must be a better (or at least shorter and more elegant) way to accomplish this process. Can anyone share such a solution?

Note: One reason I'm doing this is that, sometimes, getent group GID is a bit finicky where I work. I've looked at some other posts, e.g. this one, but it didn't have the answer I wanted.

A nicer-to-read version of the id output which IS NOT THE SAME AS WHAT THE CONSOLE GAVE! There are newline characters after (Users) (note the space after the right paren) and after (LOCAL), (no space after the comma).

$ id
uid=1(me) gid=545(Users) 
groups=545(Users),66049(CONSOLE LOGON),
11(Authenticated Users),4095(CurrentSession),66048(LOCAL)

Real id output:

$ id
uid=1(me) gid=545(Users) groups=545(Users),66049(CONSOLE LOGON),11(Authenticated Users),4095(CurrentSession),66048(LOCAL)

Upvotes: 6

Views: 1422

Answers (5)

Gautam
Gautam

Reputation: 1932

Using sed and awk :

$ id | sed 's/,/\n/g' | awk -F '[()=]' '{print $(NF-1)","$(NF-2)}'

Upvotes: 2

Allan
Allan

Reputation: 12438

And there comes perl:

$ id | perl -pe "s/.*=/,/;s/,(\d+)\(([^)]+)\)/'\2',\1\n/g"                                                                 
'arobert',1000
'adm',4
'cdrom',24
'sudo',27
'dip',30
'plugdev',46
'lpadmin',113
'sambashare',128

Explanations:

Two find and replace commands will be executed:

  • s/.*groups=/,/ is used to remove everything before the groups definition
  • s/,(\d+)\(([^)]+)\)/'\2',\1\n/g will put in place the following actions detailed @demo

It would be difficult to write something shorter than this. Also if you are already good with sed and regex, than perl can be a nice plus to add to your list of skills.

As mentioned by Ed Morton, the current perl command generates an extra EOL at the end of the output. If you want to remove it you can use the following enhanced perl command:

$ id | perl -pe "s/.*=/,/;s/,(\d+)\(([^)]+)\)/'\2',\1\n/g;s/\n\n/\n/"

Thanks Ed!!!

Upvotes: 5

Ed Morton
Ed Morton

Reputation: 203324

awk -v RS=, -F'[()=]' '{print "\047"$(NF-1)"\047,"$(NF-2)}'

e.g. given this input data:

$ cat file
uid=1(me) gid=545(Users) groups=545(Users),66049(CONSOLE LOGON),11(Authenticated Users),4095(CurrentSession),66048(LOCAL)

and using cat file in place of id:

$ cat file | awk -v RS=, -F'[()=]' '{print "\047"$(NF-1)"\047,"$(NF-2)}'
'Users',545
'CONSOLE LOGON',66049
'Authenticated Users',11
'CurrentSession',4095
'LOCAL',66048

Upvotes: 5

James Brown
James Brown

Reputation: 37404

$ id |
  awk 'BEGIN{ RS=OFS=",";q="\047" }
  {
      n=split($0,a,"=")
      split(a[n],a,"[()]")
      print q a[2] q,a[1]
  }'
'Users',545
'CONSOLE LOGON',66049
'Authenticated Users',11
'CurrentSession',4095
'LOCAL',66048

Works nicely with gawk and mawk but bwk outputed an extra broke the last line:

'',

Upvotes: 2

RavinderSingh13
RavinderSingh13

Reputation: 133458

Following awk may help you on same.

awk -v s1="'" -F"[)(=,]"  '/uid/{print s1 $(NF-1) s1 OFS $(NF-2);next} /groups/{print s1 $6 s1 OFS s1 $5 s1 ORS s1 $(NF-2) s1 OFS $(NF-3);next} /CurrentSession/{print s1 $2 s1 OFS $1 ORS s1 $(NF-1) s1  OFS $(NF-2)}' OFS=,  Input_file

OR

id | awk -v s1="'" -F"[)(=,]"  '/uid/{print s1 $(NF-1) s1 OFS $(NF-2);next} /groups/{print s1 $6 s1 OFS s1 $5 s1 ORS s1 $(NF-2) s1 OFS $(NF-3);next} /CurrentSession/{print s1 $2 s1 OFS $1 ORS s1 $(NF-1) s1  OFS $(NF-2)}' OFS=, 

Adding a non-one liner form of solution too now.

awk -v s1="'" -F"[)(=,]"  '
/uid/                    {  print s1 $(NF-1) s1 OFS $(NF-2);                          next}
/groups/                 {  print s1 $6 s1 OFS s1 $5 s1 ORS s1 $(NF-2) s1 OFS $(NF-3);next}
/CurrentSession/         {  print s1 $2 s1 OFS $1 ORS s1 $(NF-1) s1  OFS $(NF-2);         }
' OFS=,   Input_file

OR

id | awk -v s1="'" -F"[)(=,]"  '
/uid/                    {  print s1 $(NF-1) s1 OFS $(NF-2);                          next}
/groups/                 {  print s1 $6 s1 OFS s1 $5 s1 ORS s1 $(NF-2) s1 OFS $(NF-3);next}
/CurrentSession/         {  print s1 $2 s1 OFS $1 ORS s1 $(NF-1) s1  OFS $(NF-2);         }
' OFS=, 

Upvotes: 3

Related Questions