Monday, March 12, 2012

Simple method to add multilevel filtering support to text producing applications

Single level text filtering seems to be becoming more common for GUIs, normally implemented with a single text entry field that the user can type a string into, thereby indicating that the displayed data should contain that string. This is a nice feature but in my opinion inadequate for larger data sets where typically one wants to successively apply multiple filters to limit the display to a result matching several conditions. This is a little bit painful to implement in a GUI application, but very easy in the text world. The recipe I have been following uses grepm, a script I wrote as the fundamental building block. This script is so simple I'll just quote it (or really its perl guts):
use strict;
use diagnostics;

my $i = 0;
  
if ($#ARGV >= 0 && $ARGV[0] eq "-i")
{
  $i = 1;
  shift @ARGV;
}

while ()
{
  my $printIt = 1;
  foreach my $pat (@ARGV)
  {
    if ($i)
    {
      if (!/$pat/i)
      {
        $printIt = 0;
        last;
      }
    }
    else
    {
      if (!/$pat/)
      {
        $printIt = 0;
        last;
      }
    }
  }   
  print if $printIt;
}

(Although I've become enamored of Ruby, the nature of this script is to be repeatedly executed as part of other small scripts, and with that purpose in mind good performance is absolutely a requirement, and Ruby does not provide that for me in all environments. Perl, meanwhile, for all its faults, is always fast, so Perl it is.)

The script simply accepts some number of text tokens. Each of these tokens is interpreted as a regular expression that can be applied to data coming from standard input; lines which match all of the regular expressions are passed through, with everything else getting discarded. If there are no arguments to the script, then everything gets passed through.

With this building block in hand, it is a simple matter to take arbitrary scripts and bolt it on internally after shifting away commandline arguments which do not pertain to the filter. For a contrived example:

#!/bin/sh
some_arg=$1
shift

some_other_arg=$2
shift

Do_some_stuff $some_arg $some_other_arg | grepm $*


And we are done. Since the script has executed a shift for each of the arguments that it pays attention to, remaining arguments can be safely passed on to grepm to serve as filters. If there are no additional arguments, grepm has no effect, simply passing through all the data it sees. But if we do want to filter the output, this occurs with nearly no impact on the structure and complexity of the calling script. Now, for example, when I am interested in getting a listing of all the OEL VMs owned by my colleague Olfat which include the product AS10G and had an upgrade, I can easily generate what I want by calling my simple script lmd with additional filtering arguments:


% lmd olfat OEL AS10G upgraded


This yields the desired data set:


adc AS10G10.1.4.3 Upgraded to AS11GPS1 DB112-133.140-allcompconfig/oel5u5x86-2/6272, fusionmats2, false, AS10G10.1.4.3 Upgraded to AS11GPS1 DB112-133.140-allcompconfig, undeployed,2822000,0,0, olfat.aly@oracle.com, lib,1411000,1411000,46336333, null/507 -> null/538 -> null/622 -> null/626 -> null/675 -> null/733 -> null/735 -> oel5u5x86-2/743 -> oel5u5x86-2/6272, undeployed, , alwaysup=yes importance=10, ,0, ,342, 140.84.133.140
adc stage9-AS10G10.1.4.3 Upgraded to AS11GPS1 DB112/oel5u5x86-2/8975, fusionmats2, false, stage9-AS10G10.1.4.3 Upgraded to AS11GPS1 DB112, undeployed,28086000,0,0, olfat.aly@oracle.com, work,14043000,14043000,58968333, null/507 -> null/538 -> null/622 -> null/626 -> null/675 -> null/733 -> null/735 -> oel5u5x86-2/743 -> oel5u5x86-2/8975, undeployed, , importance=10, ,0, ,52, 140.84.133.120
adc AS10G10.1.4.3 Upgraded to AS11GPS1 DB112 - backup/oel5u5x86-2/743, fusionmats2, false, AS10G10.1.4.3 Upgraded to AS11GPS1 DB112 - backup, undeployed,642000,0,0, olfat.aly@oracle.com, lib,321000,321000,45085833, null/507 -> null/538 -> null/622 -> null/626 -> null/675 -> null/733 -> null/735 -> oel5u5x86-2/743, undeployed, , alwaysup=yes importance=10, ,0, ,504, 140.84.131.230
adc AS10G10.1.4.3 Upgraded to AS11GPS2 DB112 - backup/oel5u5x86-2/843, fusionmats2, false, AS10G10.1.4.3 Upgraded to AS11GPS2 DB112 - backup, undeployed,34000,0,0, olfat.aly@oracle.com, lib,17000,13035000,57799833, null/507 -> null/538 -> null/622 -> null/626 -> null/675 -> null/733 -> null/735 -> null/744 -> oel5u5x86-2/843, undeployed, , alwaysup=yes importance=10, ,0, ,0, 140.84.131.230

No comments:

Post a Comment