dwhite20899 has asked for the wisdom of the Perl Monks concerning the following question:

A friend of mine wants tools like "wc -l" and "split" from unix on his windows box, and fortunately he is allowed to run Perl. Here's what I came up with. My problem is coming up with appropriate test cases; I need a second (or more) pair of eyes . Here's linect.pl:
#!/usr/bin/perl -w use strict; use vars qw( $filename ); ($filename = shift) or die "Usage: $0 filename\n"; open(FIN,"$filename") or die "$0 : cannot read file \"$filename\"\n"; # assume it is a text file while(<FIN>) { } print sprintf("%8s",$.) , " $filename\n"; close(FIN); exit;
And here's split.pl
#!/usr/bin/perl -w use strict; use vars qw( $linect $filename $prefix $i $postfix ); ($linect = shift) or die "Usage: $0 lines_out filename new_name \n"; $linect = int($linect); if ($linect < 1) { print STDERR "$0 : cannot split less than 1 lines\n"; exit; } ($filename = shift) or die "Usage: $0 lines_out filename new_name \n"; ($prefix = shift) or die "Usage: $0 lines_out filename new_name \n"; $i = 0; $postfix = sprintf("%02d",$i); open(FIN,"$filename") or die "$0 : cannot read file \"$filename\"\n"; open(FOUT,">$prefix.$postfix") or die "$0 : cannot write file \"$prefi +x.$postfix\"\n"; # assume it is a text file while(<FIN>) { print FOUT $_ ; if (($. % $linect) == 0) { close(FOUT); $i++; $postfix = sprintf("%02d",$i); open(FOUT,">$prefix.$postfix") or die "$0 : cannot write file +\"$prefix.$postfix\"\n"; } } close(FIN); exit;
I assumed these would be text files, not binary, and I kept Getopt out of it on purpose.

Replies are listed 'Best First'.
Re: mimicing wc and split
by BrowserUk (Patriarch) on Oct 05, 2006 at 01:48 UTC

    I'd point your freind here. It contains native ports of both of those and about 30 more utilities.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Brilliant! Your link and tilly's will are a gold mine. When I was stuck on windows, I used the native MKS toolkit stuff; my friend can't put cygwin on (I'd suggested that).

      Thanks!

Re: mimicing wc and split
by tilly (Archbishop) on Oct 05, 2006 at 01:39 UTC
    What is your reason for keeping core modules out of it? If you have Perl, you should have all of Perl!

    If you're willing to keep core modules out of it, there are pure Perl versions of both wc and split available at http://ppt.perl.org/what.html that are more functional than yours are, and are already tested.

    (Of course the best solution is to have your friend install Cygwin.)

Re: mimicing wc and split
by graff (Chancellor) on Oct 05, 2006 at 02:48 UTC
    The previous replies are more worth pursuing than mine, but just to be picky, I'll point out:

    To emulate unix "wc -l", you should accept data from STDIN, and you should accept multiple file name args on the command line, reporting the line count for each file in succession:

    #!/usr/bin/perl -w use strict; if ( @ARGV ) { for my $file ( @ARGV ) { $. = 0; open( I, $file ) or do { warn "$0: open failed for file $file: $!\n"; next; } while (<I>) {} printf( "%8d %s\n", $., $file ); } } else { while (<>) {} printf( "%8d\n", $. ); }

    As for your version of "split", the only thing I see wrong is that if the line count of an input file happens to be a multiple of the selected line count for output, you'll open an extra file for output, and will close it without having written anything to it. No big deal, except some users might get confused, misled or even tripped up by having an extra file (which happens to be empty) when the process is done. Here's a simplified version that avoids that problem:

    #!/usr/bin/perl -w use strict; my $Usage = "Usage: $0 line_count input.file output_name\n"; ( @ARGV == 3 and $ARGV[0] =~ /^\d+$/ and -f $ARGV[1] ) or die $Usage; my ( $line_limit, $infile, $outname ) = @ARGV; my $outid = 0; open( I, $infile ) or die "$0: open for input failed on $infile: $!\n$ +Usage"; while (<IN>) { if ( $. % $line_limit == 1 ) { close OUT if ( $outid ); my $outfile = sprintf( "%s.%03d", $outname, ++$outid ); open( OUT, ">", $outfile ) or die "$0: open for output failed +on $outfile\n"; } print OUT; } close OUT;
      syntax error at 576460.pl line 11, near ") {" syntax error at 576460.pl line 14, near "}" Execution of 576460.pl aborted due to compilation errors.

      missig ; after the do{} block in wc. Didn't test? ;-)

      #!/usr/bin/perl -w use strict; my ($i,$c) = @ARGV > 1 ? 8 : 0; (-z $ARGV[0] and printf ("%${i}d %s\n", 0, shift) and @ARGV or exit) +if @ARGV; while(<ARGV> || eof ARGV) { $c++; if (eof(ARGV)) { printf "%${i}d %s\n", $., $ARGV; $. = 0; $ARGV[0] and -z $ARGV[0] and printf "%${i}d %s\n", 0, shift; @ARGV || last; } } printf "%${i}d total\n",$c if $i;

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Argh! Yep, I didn't think about a file the size of the split block. Thanks for the nice catch.