#!/usr/bin/perl =head1 NAME randomline -- pick a single randline from a file (ignore comment/blank lines) =head1 SYNOPSIS randomline [option] file... > random_line Options: -v output line to standard error channel as well -l print file line number of the pick (for debuging) -e print the element number (line number over all files) =head1 DESCRIPTION This program is based on a program in the Perl (Camel) Book, page 246, which does a single pass on a file without storing the the whole file into memory. It is based on the proability that the current line would be picked IF it is the last line of the file. It works out very even and clean. Any comment and blank lines in the input are ignored. If no comments are present in the file the the line number (-l) and element number (-e) will be the same. Ignored Input... * Anything following a '#' is stripped, and white spave before it removed * Empty lines or only consisting of white space * Any line starting with '!' (cpp comment) Other than as described, white space is not removed from lines =head1 SEE ALSO The GNU "shuf" command (does not ignore comment lines) grep -v "^#" file | shuf -n 1 Unlike this program, the "shuf" command reads in the whole file into memory before picking a line. =head1 AUTHOR Anthony Thyssen =cut sub Usage { use Pod::Usage; pod2usage("@_"); exit 10; } ARGUMENT: # Multi-switch option handling while( @ARGV && $ARGV[0] =~ s/^-(?=.)// ) { $_ = shift; { m/^$/ && do { next }; # next argument m/^-$/ && do { last }; # End of options m/^\?/ && do { Usage }; # Usage Help s/^v// && do { $verbose++; redo }; # output to stderr too s/^l// && do { $out_linenum++; redo }; # line number of pick (debug) s/^e// && do { $out_element++; redo }; # element number of pick (debug) Usage( "Unknown Option \"-$_\"\n" ); } continue { next ARGUMENT }; last ARGUMENT; } # ----------------------------------------- # removed as first login after a reboot seemed to produce the same seed! #srand( time ^ $$ ); # perl randomises the seed better on its own. $line = 0; # line number -- determine posibility of selecting this line while(<>) { next if /^!/; # skip the '!' comments (for cpp) s/\s*#.*$//; # remove any '#' comment and leading white space next unless /\S/; # skip any resulting white space only lines $num++; # current element number (ignoring comments, and blanks) ( $pick = $_, $l=$., $n=$num ) if rand( $num ) < 1; # element be picked if it was the last line } $pick =~ s/\s*$//; # remove any extra spaces at end of line print $pick, "\n"; print STDERR $pick, "\n" if $verbose; print STDERR "$l\n" if $out_linenum; print STDERR "$n\n" if $out_element;