Reputation: 1428
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
Reputation: 1932
Using sed and awk :
$ id | sed 's/,/\n/g' | awk -F '[()=]' '{print $(NF-1)","$(NF-2)}'
Upvotes: 2
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 definitions/,(\d+)\(([^)]+)\)/'\2',\1\n/g
will put in place the following actions detailed @demoIt 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
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
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
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