Date: Sun, 01 Jul 2001 08:41:14 -0400 From: Benjamin Goldberg Subject: Re: converting shell "sort" command to perl.. Message-Id: <3B3F1A6A.761A63FE@earthlink.net> Patrick Erler wrote: > > Benjamin Goldberg wrote in > news:3B3C1A30.54DC5E6@earthlink.net: > > > Patrick Erler wrote: > >> now i want to convert the script to perl, no big problem, but this > >> command i just don't get converted: > >> > >> sort -k 4.9b,4.13n -k 4.5b,4.7M -k 4.2b,4.3n -k4.14b,4.15n > >> -k 4.17b,4.18n -k 4.20b,4.21n > >> > >> what it sorts is a simple apache log like this: > >> 213.83.52.132 - - [28/Jun/2001:20:29:43 +0200] "GET / HTTP/1.0" 200 > >> 3392 "-" "check_http/1.32.2.6 (netsaint-plugins 1.2.9-4)" > >> > >> ok, i could call the shell but i really would like to do it in > >> perl... > [Benjamins code deleted] > > I could have used Time::Local rather than packing the date > > components as bytes, but there is no need to bring it in, since it > > isn't really needed. > > > > Note that this code is untested. > thanks benjamin.. i corrected some bugs in the code.. here is a tested > version: > > #!/usr/bin/perl -w > use strict; > > #$#ARGV >= 1 or die "Usage:\n\t$0 [logfile]\n"; Why comment this line out? You don't checking arguments? > > my %mon; > @mon{qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)} = (0..11); > > my $stabilizer = 0; > > open my $ifh, "<", $ARGV[0] # my $ifh closed at end of do-block. > or die "Could not open $ARGV[0] for r: $!\n"; > rename( $ARGV[0], $ARGV[0] . ".bak" ) > or die "Could not rename $ARGV[0] to $ARGV[0].bak: $!\n"; > open my $ofh, ">", $ARGV[0] # note there is no "my" here. > or die "Could not open $ARGV[0] for w: $!\n"; There was a purpose of putting this inside the do {} block in my version. Moving it up here wasn't the right thing to do. > print $ofh substr $_, 11 for > sort > map { > # 213.83.52.132 - - [28/Jun/2001:20:29:43 stuff > m/^\S* \S* \S* (\S*)/; > my @date = unpack "xa2xa3xa4xa2xa2xa2", $1; > pack "ncccccNa*", > $date[2], $mon{$date[1]}, @date[0,3,4,5], > ++$stabilizer, $_; > } do {{ # double leftbrace to make a block > ($ifh, $ofh) = (*STDIN, *STDOUT), last if @ARGV == 0; > } # end of block; "last" from above skips to here. > <$ifh>; > }; What you have inside of the do block is incorrect. Consider what happens if the script is called with no arguments. Originally, I'd had the open for $ifh and $ofh inside the do block, after the test for if @ARGV == 0, so that if no arguments were passed, no file was opened. > close $ofh or die "Couldn't close $ARGV[0]: $!\n" if @ARGV == 1; Since you moved $ifh to toplevel, you ought to have included a close for it, too, here. > __END__ > > only the simplest thing with this code i don't get solved right now.. > how should this line look like correctly? > > $#ARGV >= 1 or die "Usage:\n\t$0 [logfile]\n"; > > thanks benjamin, you've been a great help! Well, if you want to write the script to allow only one argument, no more no less, I would do: die "Usage:\n\t$0 logfile\n" unless @ARGV == 1; If you want it to accept either 0 or 1 arguments, then: die "Usage:\n\t$0 [logfile]\n" unless @ARGV <= 1; Rewriting the script to accept exactly one argument, this becomes: #!/usr/bin/perl -w use strict; die "Usage:\n\t$0 logfile\n" unless @ARGV == 1; my %mon; @mon{qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)} = (0..11); my ($stabilizer, $ofh) = 0; print $ofh substr $_, 11 for sort map { # 213.83.52.132 - - [28/Jun/2001:20:29:43 stuff m/^\S* \S* \S* (\S*)/; my @date = unpack "xa2xa3xa4xa2xa2xa2", $1; pack "ncccccNa*", $date[2], $mon{$date[1]}, @date[0,3,4,5], ++$stabilizer, $_; } do { my ($fn, $ifh) = $ARGV[0]; open $ifh, "<", $fn # $ifh declared here, closes at end of scope or die "Could not open $fn for reading: $!\n"; rename( $fn, $fn . ".bak" ) or die "Could not rename $fn to $fn.bak: $!\n"; open $ofh, ">", $fn # $ofh declared up above, explicitly closed or die "Could not open $fn for writing: $!\n"; <$ifh>; }; close $ofh or die "Couldn't close $ARGV[0]: $!\n"; __END__ While this code hasn't been tested, I don't see any reason for it not to work. -- The longer a man is wrong, the surer he is that he's right.