[OT] can sed handle this situation? (might require variable)

Parv parv at pair.com
Sun Apr 15 05:58:18 UTC 2007


Darn, forgot to copy to the dear list; so here it is (sent to OP
previously) ...


in message <1176603461.20274.12.camel at joe.realss.com>,
wrote Zhang Weiwu thusly...
>
> Dear list. I could not find a mailing list about 'sed' (there is
> an very inactive Yahoo Group though) so I wish to try some luck
> here.

Try, comp.unix.misc newsgroup.


> I've got a situation that looks like require using variable and
> not possible to process with sed. But I am not sure. Can someone
> suggest me if this task is out of scope of sed?

Try some variation of what Garret suggested if sed is the
requirement and skip rest of the message.


> The input document is sections of data separated by an empty new
> line
...
>    dn: uid=ABB,ou=contacts,ou=china,dc=ahk,dc=de
>    uid: ABB
>    ahkCreateTimeStamp: 19960328000000Z
>    creatorsName: cn=manager,dc=ahk,dc=de
>    createTimestamp: 20060425094550Z
>
>    dn: uid=paulblome,ou=contacts,ou=china,dc=ahk,dc=de
>    uid: paulblome
>    sn: Blome
>    createTimestamp: 20060417071950Z
>    modifiersName: cn=manager,dc=ahk,dc=de
>    modifyTimestamp: 20060630094026Z
>
> The above sample showed two sections in input data. It's required to
> process the data in following rule:
>
>    if a data section has "ahkCreateTimeStamp: abc", replace it
>    with "createTimestamp: abc" and remove the original
>    "createTimestamp: def" line;
>
> That is, the result data of above sample should be:
>
>    dn: uid=ABB,ou=contacts,ou=china,dc=ahk,dc=de
>    uid: ABB
>    createTimestamp: 19960328000000Z
>    creatorsName: cn=manager,dc=ahk,dc=de
>
>    dn: uid=paulblome,ou=contacts,ou=china,dc=ahk,dc=de
>    uid: paulblome
>    sn: Blome
>    createTimestamp: 20060417071950Z
>    modifiersName: cn=manager,dc=ahk,dc=de
>    modifyTimestamp: 20060630094026Z

Here is my version in Perl (v5.8.8; run it by giving it files to
process as command line arguments; no files are modified; output
goes to the standard output) ...

  #!/usr/local/bin/perl

  use warnings; use strict;

  my $orig = 'createTimestamp';
  my $changed = 'ahkCreateTimeStamp' ;

  #  Mapping of changed & original strings with related regular
  #  expressions.
  my %replacement;
  @replacement{ ( 'changed' , 'orig' ) } =
    map
    { [ $_
      , qr(^ \s*    #  Optional whitespace at the beginning;
            $_      #  time stamp text;
            \s* :   #  optional whitespace before colon;
            \s*     #  optional whitespace;
            \S+     #  non whitespace character sequence (time stamp);
            .* $    #  then anything or nothing else at the end.
          )xm
      ]
    }
    ( $changed , $orig )
    ;

  #  Process files, given as command line arguments.  Output is
  #  printed on standard output, no file is actually modified.
  for my $file ( @ARGV )
  {
    my $fh;
    unless ( open $fh , '<' , $file )
    {
      warn "Cannot open file '$file': $!\n" ;
      next;
    }

    update_time_stamp( \%replacement , $fh );

    close $fh or die "Cannot close '$file': $!\n" ;
  }
  exit;

  sub update_time_stamp
  {
    my ( $map , $fh ) = @_;

    my $changed = $map->{'changed'};
    my $orig = $map->{'orig'};

    #  Set input record separator to parse data in blocks.
    local $/ = "" ;
    while ( my $block = <$fh> )
    {
      #  Nothing to do if there is no ahk* string.
      next
        unless $block =~ m/$changed->[1]/
            && $block =~ m/$orig->[1]/ ;

      for ( $block )
      {
        #  Remove original replacement time stamp line.  (Order does
        #  not matter as only the text is changed not the associated
        #  time stamp value.)
        s/$orig->[1]//;

        #  Update time stamp string.
        s/$changed->[0]/$orig->[0]/;
      }

      #  Remake the block by removing empty line (caused by removal of
      #  replacement time stamp line.)
      $block =
        join "\n"
        , grep { $_ !~ m/^\s*$/ } split /\n+/ , $block
        ;

      #  Add removed new line at the end, and another as separator.
      $block .= "\n\n" ;
    }
    #  For each & every block processed ...
    continue
    {
      print $block ;
    }
  }
  __END__


  - Parv

-- 



More information about the freebsd-questions mailing list