#!/usr/bin/perl # Filename: spigot # Author: David Ljung Madison # See License: http://MarginalHacks.com/License/ my $VERSION= '1.01'; # Description: Like a faucet tap, turns the output of a text file on and off use strict; ################################################## # Setup the variables ################################################## my $PROGNAME = $0; $PROGNAME =~ s|.*/||; my ($BASENAME,$PROGNAME) = ($0 =~ m|(.*)/(.+)|) ? ($1?$1:'/',$2) : ('.',$0); ################################################## # Usage ################################################## sub fatal { foreach my $msg (@_) { print STDERR "[$PROGNAME] ERROR: $msg\n"; } exit(-1); } sub usage { foreach my $msg (@_) { print STDERR "ERROR: $msg\n"; } print STDERR < Like a faucet tap, turns the output of a text file on and off Controls: -show Show lines (or 'all') -skip Skip lines -off Turn off display when is seen -on Turn on display when is seen -ON Just turn on (similar to '-on .') -OFF Just turn off -do \"\" Execute a command -echo \"\" Print a line -d Set debug mode Examples: # A very inefficient 'cat' % $PROGNAME file # Like 'head' % $PROGNAME file -show 15 -OFF # Show everything up until '^footer' is seen % $PROGNAME file -off '^footer' # Show everything up until and including '^footer' # (The '-show 1' will show one line (the footer) but won't change on/off status) % $PROGNAME file -off '^footer' -show 1 # Show everything after we find 'START' % $PROGNAME file -OFF -on START # Show everything after (but not including) 'START' % $PROGNAME file -OFF -on START -skip 1 # Show the first two lines of 'log' then show everything from 'ERROR MSG' # until the first blank line is found, then stop processing the file % $PROGNAME log -OFF -show 2 -on "ERROR MSG" -off '^\$' # Use -echo and -do % $PROGNAME file -echo "HEADER" -ON -off INCLUDE-HERE -do "cat include" -ON # -echo at end of file % $PROGNAME file -on START -show all -echo "FOOTER" USAGE exit -1; } sub parse_args { my $opt = {}; while (my $arg=shift(@ARGV)) { if ($arg =~ /^-h$/) { usage(); } if ($arg =~ /^-d$/) { $opt->{d}=1; next; } if ($arg =~ /^-(on|show|skip|off|echo|do)$/) { push(@{$opt->{ctrl}}, [$1, shift @ARGV]); next; } if ($arg =~ /^-(ON|OFF)$/) { push(@{$opt->{ctrl}}, [$1]); next; } if ($arg =~ /^-./) { usage("Unknown option: $arg"); } push(@{$opt->{files}}, $arg); } usage("No file defined") unless $opt->{files}; $opt; } sub debug { my ($opt,@msg) = @_; return unless $opt->{d}; foreach my $msg (@msg) { print STDERR "[$PROGNAME] $msg\n"; } } ################################################## # Process a file ################################################## sub moreCtrl { my ($opt) = @_; return 0 unless $opt->{ctrl}; return 1 if @{$opt->{ctrl}}; } # What is the current ctrl? # Handle echo/do here sub currCtrl { my ($opt) = @_; return 0 unless $opt->{ctrl}; return 0 unless $opt->{ctrl}[0]; my ($cmd,$arg,@args) = @{$opt->{ctrl}[0]}; return ($cmd,$arg,@args) unless $cmd eq 'echo' || $cmd eq 'do'; if ($cmd eq 'echo') { print "$arg\n"; # Should this have an automatic newline? return nextCtrl($opt); } if ($cmd eq 'do') { system($arg); return nextCtrl($opt); } } sub nextCtrl { my ($opt) = @_; return 0 unless $opt->{ctrl}; shift @{$opt->{ctrl}}; currCtrl($opt); } # Do we start with the spigot on or off? sub start { my ($opt) = @_; return 1 unless moreCtrl($opt); # Default case, act like "cat" my ($cmd) = currCtrl($opt); return 1 unless $cmd; return 0 if grep($cmd eq $_, qw(show on)); 1; } sub process { my ($opt, $file) = @_; open(FILE,"<$file") || usage("Couldn't open file: $file"); # Process a file, turning the spigot on and off. my $on = start($opt); while() { # Can we match any controls? my $match = 1; while ($match) { # We're done if we're 'off' and we have no more controls unless (moreCtrl($opt)) { if ($on) { print; map { print } ; } $on = 0; # We're done last; } # Get the next control my ($cmd,$arg,@args) = currCtrl($opt); $match = 0; if ($cmd eq "ON") { ($on,$match) = (1,1); } elsif ($cmd eq "OFF") { ($on,$match) = (0,1); } elsif ($cmd eq "on") { ($on,$match) = (1,1) if /$arg/; } elsif ($cmd eq "off") { ($on,$match) = (0,1) if /$arg/; } elsif ($cmd eq "show") { $match = 1; print; # Current line if ($arg eq 'all') { print ; $on = 0; undef $_; } else { map { print scalar ; } 2..$arg; $_ = scalar ; # Next line } } elsif ($cmd eq "skip") { map { scalar ; } 2..$arg; $_ = scalar ; # Next line $match = 1; } nextCtrl($opt) if $match; print "$match -> cmd,on=[$cmd,$on] $_" if $opt->{d}; } print if $on && !$opt->{d}; } close(FILE); } ################################################## # Main code ################################################## sub main { my $opt = parse_args(); map { process($opt, $_) } @{$opt->{files}}; } main();