Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have file(sudoers) in which lines can be identical except for the first word in them (different users can execute the same set of commands). I am able to extract such a line using the command:

# grep -v '^ *%' /etc/sudoers |egrep "$users_in_which_I_am_interested | sort|awk '{sub(/^[ \t]+/, "")};1'

tom ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser   
jim ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser   
mark ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser  
peter ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser

(/etc/sudoers is before that prepared to remove leading and trailing tabs and spaces and replace all multiple whitespaces between words single space). Those lines are identical except for the user. I want to be able to extract lines which have the same command statements configured with the same permissions but different users, and assign the username to a variable and run it through a loop.

# grep -v '^ *%' /etc/sudoers |egrep "$users_in_which_I_am_interested | sort|awk '{sub(/^[ \t]+/, "")};1'| uniq -cf 1
4 tom ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser

The problem for me comes here - how to find all the lines in the file which contain

"ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser"

and assign the user in those lines to a variable? "grep"-ing for the string is not easily possible, it is an unknown string and might contain many characters that have to be escaped. ksh, awk and sed can be used (no perl/python and other scr. languages).

share|improve this question
awk '
  {user = $1; $1 = ""; users[$0] = users[$0] sep user; sep = " "}
  END {for (key in users) {print key ">" users[key]}}

Given your sample input, this produces

 ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser>tom jim mark peter
share|improve this answer
It always amazes me how much you can do with awk – Nifle Jul 17 '11 at 12:27

I know you didn't want a perl solution but here is one anyway. It has the advantage that it can handle if the allowed commands are in different order.

is treated as equal to

use strict;
use warnings;

my %hash;

# reads all lines from STDIN
while(<>) {
    chomp;  # removes leading/trailing whitespace

    #splits the input string on whitespace
    my ($user, undef, undef, $cmds) = split;    

    # pulls out list of allowed commands
    my($NP, $cmdlist) = split(/:/, $cmds);

    # Sorts the list of commands and puts it together again
    $cmds = "$NP:".join(',', sort split(/,/, $cmdlist));

    # if the command exists in the hash with a user
    # add the nest user else just adds user                      
    $hash{$cmds} = $hash{$cmds}? "$hash{$cmds} $user" : $user;

# print all                                          
foreach my $key (keys %hash) {
    print "$key | ", $hash{$key} ,"\n";
share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .