Question

Because of the more tedious way of adding hosts to be monitored in Nagios (it requires defining a host object, as opposed to the previous program which only required the IP and hostname), I figured it'd be best to automate this, and it'd be a great time to learn Perl, because all I know at the moment is C/C++ and Java.

The file I read from looks like this:

xxx.xxx.xxx.xxx hostname #comments. i.dont. care. about

All I want are the first 2 bunches of characters. These are obviously space delimited, but for the sake of generality, it might as well be anything. To make it more general, why not the first and third, or fourth and tenth? Surely there must be some regex action involved, but I'll leave that tag off for the moment, just in case.

Was it helpful?

Solution

The one-liner is great, if you're not writing more Perl to handle the result.

More generally though, in the context of a larger Perl program, you would either write a custom regular expression, for example:

if($line =~ m/(\S+)\s+(\S+)/) {
     $ip = $1;
     $hostname = $2;
}

... or you would use the split operator.

my @arr = split(/ /, $line);
$ip = $arr[0];
$hostname = $arr[1];

Either way, add logic to check for invalid input.

OTHER TIPS

Let's turn this into code golf! Based on David's excellent answer, here's mine:

perl -ane 'print "@F[0,1]\n";'

Edit: A real golf submission would look more like this (shaving off five strokes):

perl -ape '$_="@F[0,1]
"'

but that's less readable for this question's purposes. :-P

Here's a general solution (if we step away from code-golfing a bit).

#!/usr/bin/perl -n
chop;                     # strip newline (in case next line doesn't strip it)
s/#.*//;                  # strip comments
next unless /\S/;         # don't process line if it has nothing (left)
@fields = (split)[0,1];   # split line, and get wanted fields
print join(' ', @fields), "\n";

Normally split splits by whitespace. If that's not what you want (e.g., parsing /etc/passwd), you can pass a delimiter as a regex:

@fields = (split /:/)[0,2,4..6];

Of course, if you're parsing colon-delimited files, chances are also good that such files don't have comments and you don't have to strip them.

A simple one-liner is

perl -nae 'print "$F[0] $F[1]\n";'

you can change the delimiter with -F

David Nehme said:

perl -nae 'print "$F[0] $F[1}\n";

which uses the -a switch. I had to look that one up:

-a   turns on autosplit mode when used with a -n or -p.  An implicit split
     command to the @F array is done as the first thing inside the implicit
     while loop produced by the -n or -p.

you learn something every day. -n causes each line to be passed to

LINE:
    while (<>) {
        ...             # your program goes here
    }

And finally -e is a way to directly enter a single line of a program. You can have more than -e. Most of this was a rip of the perlrun(1) manpage.

Since ray asked, I thought I'd rewrite my whole program without using Perl's implicitness (except the use of <ARGV>; that's hard to write out by hand). This will probably make Python people happier (braces notwithstanding :-P):

while (my $line = <ARGV>) {
    chop $line;
    $line =~ s/#.*//;
    next unless $line =~ /\S/;
    @fields = (split ' ', $line)[0,1];
    print join(' ', @fields), "\n";
}

Is there anything I missed? Hopefully not. The ARGV filehandle is special. It causes each named file on the command line to be read, unless none are specified, in which case it reads standard input.

Edit: Oh, I forgot. split ' ' is magical too, unlike split / /. The latter just matches a space. The former matches any amount of any whitespace. This magical behaviour is used by default if no pattern is specified for split. (Some would say, but what about /\s+/? ' ' and /\s+/ are similar, except for how whitespace at the beginning of a line is treated. So ' ' really is magical.)

The moral of the story is, Perl is great if you like lots of magical behaviour. If you don't have a bar of it, use Python. :-P

To Find Nth to Mth Character In Line No. L --- Example For Finding Label


@echo off

REM Next line = Set command value to a file  OR  Just Choose Your File By Skipping The Line
vol E: > %temp%\justtmp.txt
REM  Vol E:  = Find Volume Lable Of Drive E

REM  Next Line to choose line line no. +0 = line no. 1 
for /f "usebackq delims=" %%a in (`more +0 %temp%\justtmp.txt`) DO (set findstringline=%%a& goto :nextstep)

:nextstep

REM  Next line to read nth to mth Character  here 22th Character to 40th Character
set result=%findstringline:~22,40%

echo %result%
pause
exit /b

Save as find label.cmd

The Result Will Be Your Drive E Label

Enjoy

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top