开发者

How can I reformat the GECOS field with Perl or awk?

I want to scan the passwd file and change the order of words in the comment field from firstname lastname to lastname firstname, and force the surname to capitals.

So, change every line from:

开发者_JS百科
jbloggs:x:9999:99:Joe Bloggs:/home/jbloggs:/bin/ksh

to:

jbloggs:x:9999:99:BLOGGS Joe:/home/jbloggs:/bin/ksh

I'm new to Perl and I'm having problems with different field separators in awk. Appreciate any help.


Use Passwd::Unix or Passwd::Linux.


$ awk -v FS=":" '{split($5, a, " "); name = toupper(a[2]) " " a[1]; gsub($5, name); print $0}' passwd

Won't work if you have middle names though.

Edit: easier to read version

awk -v FS=":" '
{
    split($5, name_parts, " ")
    name = toupper(name_parts[2]) " " name_parts[1]
    gsub($5, name)
    print $0
}' passwd


Stand-alone example:

use strict;
use warnings;
my $s = 'jbloggs:x:9999:99:Joe Bloggs:/home/jbloggs:/bin/ksh';
my @tokens = split /:/, $s;
my ($first, $last) = split /\s+/, $tokens[4];
$tokens[4] = uc($last) . " $first";
print join(':', @tokens), "\n";

__END__
jbloggs:x:9999:99:BLOGGS Joe:/home/jbloggs:/bin/ksh

As a script (output to STDOUT; must redirect output to a file):

use strict;
use warnings;
while (<>) {
    chomp;
    my @tokens = split /:/;
    my ($first, $last) = split /\s+/, $tokens[4];
    $tokens[4] = uc($last) . " $first";
    print join(':', @tokens), "\n";
}


This will process the file as you read it and put the new format entries into the array @newEntries.

open PASSWD, "/etc/passwd";
while(<PASSWD>) {
    @fields = split /:/;
    ($first, $last) = split (/\s/, $fields[4]);
    $last = uc $last;
    $fields[4] = "$last $first";
    push @newEntries, join(':', @fields);
}


$ awk -F":" ' { split($5,a," ");$5=toupper(a[2])" "a[1] } 1 ' OFS=":" /etc/passwd
jbloggs:x:9999:99:BLOGGS Joe:/home/jbloggs:/bin/ksh


$ perl -pe 's/^((.*:){4})(\S+)\s+(\S+?):/$1\U$4\E, $3:/' \
    /etc/passwd >/tmp/newpasswd

To rewrite only those users who have logged in within the past sixty days according to lastlog, you might use

#! /usr/bin/perl -n

use warnings;
use strict;

use Date::Parse;

my($user) = /^([^:]+):/;
die "$0: $ARGV:$.: no user\n" unless defined $user;

if ($user eq "+") {
  next;
}

my $lastlog = (split " ", `lastlog -u "$user" | sed 1d`, 4)[-1];
die "$0: $ARGV:$.: lastlog -u $user failed\n"
  unless defined $lastlog;

my $time_t = str2time $lastlog;

# rewrites users who've never logged in
#next if defined $time_t && $time_t < ($^T - 60 * 24 * 60 * 60);

# users who have logged in within the last sixty days
next unless defined $time_t && $time_t >= ($^T - 60 * 24 * 60 * 60);

s/^((.*:){4})(\S+)\s+(\S+?):/$1\U$4\E, $3:/;
print;

as in

$ ./fixusers /etc/passwd >/tmp/fixedusers
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜