Одинаковые строки, кроме первого слова, поместите первое слово в переменную
У меня есть файл (sudoers), в котором строки могут быть идентичны, за исключением первого слова в них (разные пользователи могут выполнять один и тот же набор команд). Я могу извлечь такую строку с помощью команды:
# 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 до этого подготовлен для удаления начальных и конечных вкладок и пробелов и замены всех нескольких пробелов между словами на один пробел). Эти строки идентичны, за исключением пользователя. Я хочу иметь возможность извлекать строки, которые имеют одинаковые операторы команд, настроенные с одинаковыми разрешениями, но разными пользователями, и назначать имя пользователя переменной и запускать его через цикл.
# 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
Проблема для меня возникает здесь - как найти все строки в файле, которые содержат
"ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser"
и назначить пользователя в этих строках переменной? "grep"-ing для строки не легко возможно, это - неизвестная строка и может содержать много символов, которые должны быть экранированы. Можно использовать ksh, awk и sed (без perl / python и других языков scr.).
2 ответа
awk '
  {user = $1; $1 = ""; users[$0] = users[$0] sep user; sep = " "}
  END {for (key in users) {print key ">" users[key]}}
'
Учитывая ваш пример ввода, это производит
 ALL = NOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser>tom jim mark peter
Я знаю, что вы не хотели Perl-решение, но оно все равно есть. Преимущество заключается в том, что он может обрабатывать, если разрешенные команды находятся в другом порядке.
ТакNOPASSWD:/usr/bin/pwdadm,/usr/bin/chsec,/usr/bin/chuser
рассматривается как равныйNOPASSWD:/usr/bin/chuser,/usr/bin/pwdadm,/usr/bin/chsec
#!/bin/perl
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";
}