3

I'm editing my question to add more details

The script executes the command and redirects the output to a text file.

The script then parses the text file to match the following string " Standard 1.1.1.1"

The output in the text file is :

             Host Configuration
             ------------------

             Profile              Hostname
             --------             ---------

             standard             1.1.1.1
             standard             1.1.1.2

The code works if i search for either 1.1.1.1 or standard . When i search for standard 1.1.1.1 together the below script fails.

this is the error that i get "Unable to find string: standard 172.25.44.241 at testtest.pl

#!/usr/bin/perl
use Net::SSH::Expect;     
use strict;
use warnings;
use autodie;

open (HOSTRULES, ">hostrules.txt") || die "could not open output file";
my $hos = $ssh->exec(" I typed the command here  ");
print HOSTRULES ($hos);
close(HOSTRULES);

sub find_string
{
my ($file, $string) = @_;
open my $fh, '<', $file;
while (<$fh>) {
    return 1 if /\Q$string/;
}
die "Unable to find string: $string";
}

find_string('hostrules.txt', 'standard 1.1.1.1');
6
  • Please define "Thrown and error" what do you expect to happen when it is not found? Commented Jun 3, 2014 at 16:50
  • I have added my updated script below.The script throws the following error. ""Name "main::OUTPUTFILE" used only once: possible typo at sm.pl line 19. Unable to find string: Object-cache at sm.pl line 27." Commented Jun 3, 2014 at 17:00
  • You are using a fancy electric screwdriver to pound nails to a board. input_record_separator is not meant to be used for matching. Commented Jun 3, 2014 at 18:54
  • 1) pedantically, the "used only once" message is a warning, and not an error. 2) there are not 27 lines of code in your sample. I count 11. Commented Jun 3, 2014 at 20:59
  • @len Jaffe, I have added more details to the question.Could you please take a look at it and let me know what needs to be done? Commented Jun 4, 2014 at 21:10

4 Answers 4

2

Perhaps write a function:

use strict;
use warnings;
use autodie;

sub find_string {
    my ($file, $string) = @_;
    open my $fh, '<', $file;
    while (<$fh>) {
        return 1 if /\Q$string/;
    }
    die "Unable to find string: $string";
}

find_string('output.txt', 'object-cache enabled');

Or just slurp the entire file:

use strict;
use warnings;
use autodie;

my $data = do {
    open my $fh, '<', 'output.txt';
    local $/;
    <$fh>;
};

die "Unable to find string" if $data !~ /object-cache enabled/;
Sign up to request clarification or add additional context in comments.

2 Comments

I have posted my code above.I'm using the function that you provided. The script fails, when i integrated the function with my code.
For the function that you have provided ,how do I test the negative case. I mean I would like to check if the string is NOT present in the text file. say for example i want to check that the the string "object-cache enabled" is NOT_PRESENT in the file output.txt
0

You're scanning a file for a particular string. If that string is not found in that file, you want an error thrown. Sounds like a job for grep.

use strict;
use warnings;
use features qw(say);
use autodie;

use constant {
    OUTPUT_FILE   => 'output.txt',
    NEEDED_STRING => "object-cache enabled",
};

open my $out_fh, "<", OUTPUT_FILE;
my @output_lines = <$out_fh>;
close $out_fh;
chomp @output_lines;

grep { /@{[NEEDED_STRING]}/ } @output_lines  or
    die qq(ERROR! ERROR! ERROR!);    #Or whatever you want

The die command will end the program and exit with a non-zero exit code. The error will be printed on STDERR.

I don't know why, but using qr(object-cache enabled), and then grep { NEEDED_STRING } didn't seem to work. Using @{[...]} allows you to interpolate constants.

Instead of constants, you might want to be able to pass in the error string and the name of the file using GetOptions.

I used the old fashion <...> file handling instead of IO::File, but that's because I'm an old fogy who learned Perl back in the 20th century before it was cool. You can use IO::File which is probably better and more modern.


ADDENDUM

Any reason for slurping the entire file in memory? - Leonardo Herrera

As long as the file is reasonably sized (say 100,000 lines or so), reading the entire file into memory shouldn't be that bad. However, you could use a loop:

use strict;
use warnings;
use features qw(say);
use autodie;

use constant {
    OUTPUT_FILE   => 'output.txt',
    NEEDED_STRING => qr(object-cache enabled),
};

open my $out_fh, "<", OUTPUT_FILE;
my $output_string_found;   # Flag to see if output string is found

while ( my $line = <$out_fh> ) {
    if ( $line =~ NEEDED_STRING ){
        $output_string_found = "Yup!"
        last;   # We found the string. No more looping.
    }
}
die qq(ERROR, ERROR, ERROR) unless $output_string_found;

This will work with the constant NEEDED_STRING defined as a quoted regexp.

7 Comments

Any reason for slurping the entire file in memory?
No reason except it allows me to use grep and keep the program simple. Otherwise, I'd do a loop while reading each line. If the output file isn't too large (Let's say less than 100,000 lines), slurping the file should be okay.
I just tested to see if grep works with a file handle. Nope.
Added to my answer to not use grep and slurp up the whole file.
Yeah, the second example contains a small error (a leftover from your first example). I think the second answer is the correct approach (I used the same idea in my answer.)
|
0
perl -ne '/object-cache enabled/ and $found++; END{ print "Object cache disabled\n" unless $found}' < input_file

This just reads the file a line at a time; if we find the key phrase, we increment $found. At the end, after we've read the whole file, we print the message unless we found the phrase.

If the message is insufficient, you can exit 1 unless $found instead.

I suggest this because there are two things to learn from this:

  1. Perl provides good tools for doing basic filtering and data munging right at the command line.
  2. Sometimes a simpler approach gets a solution out better and faster.

This absolutely isn't the perfect solution for every possible data extraction problem, but for this particular one, it's just what you need.

The -ne option flags tell Perl to set up a while loop to read all of standard input a line at a time, and to take any code following it and run it into the middle of that loop, resulting in a 'run this pattern match on each line in the file' program in a single command line.

END blocks can occur anywhere and are always run at the end of the program only, so defining it inside the while loop generated by -n is perfectly fine. When the program runs out of lines, we fall out the bottom of the while loop and run out of program, so Perl ends the program, triggering the execution of the END block to print (or not) the warning.

If the file you are searching contained a string that indicated the cache was disabled (the condition you want to catch), you could go even shorter:

perl -ne '/object-cache disabled/ and die "Object cache disabled\n"' < input_file

The program would scan the file only until it saw the indication that the cache was disabled, and would exit abnormally at that point.

2 Comments

How to parse a text file and check if the string is not present ?
The first example is a "fail if I didn't find X"; second is a "fail if I found something I didn't want".
0

First, why are you using Net::SSH::Expect? Are you executing a remote command? If not, all you need to execute a program and wait for its completion is system.

system("cmd > file.txt") or die "Couldn't execute: $!";

Second, it appears that what fails is your regular expression. You are searching for the literal expression standard 1.1.1.1 but in your sample text it appears that the wanted string contains either tabs or several spaces instead of a single space. Try changing your call to your find_string function:

find_string('hostrules.txt', 'standard\s+1.1.1.1'); # note '\s+' here

1 Comment

I'm using Net::SSH::Expect as i need to login to a cisco router to execute the commands. and '\s+' isn't working. I tried. any other suggestions ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.