1828675 Members
2213 Online
109984 Solutions
New Discussion

perl question

 
SOLVED
Go to solution
limak
Occasional Advisor

perl question

perl -i -n -e 'print $_; print "192.168.1.3 \myhost3\n" if /^192.168.4 \myhost4/;' /etc/hosts

I'm trying to get this work, search for an existed line and add right below it in the /etc/hosts file in sequence?

Example:
192.168.1.1 myhost1
192.168.1.2 myhost2
192.168.1.3 myhost3

192.168.1.10 myhost10

10 points for the best solution
18 REPLIES 18
H.Merijn Brand (procura
Honored Contributor

Re: perl question

perl -pi -e 'm/^192.168.1.4\s+myhost4/ and s/$/\n192.168.1.3\tmyhost3' /etc/hosts

Enjoy, Have FUN! H.Merijn
Enjoy, Have FUN! H.Merijn
Hein van den Heuvel
Honored Contributor

Re: perl question

Hmm,

Your question talks about adding a line after a recognized line, but the numbers in the code attempt suggest the line should go before.

Merijn has the smart solution with a replace of 'nothing' with a new line and then have the implied (-p) print, print out the double-line string.

To KISS, i like your 'just print first, then see if you need to print more'.

This works for me on XP (where I needed to escape quotes):

# perl -n -ix -e "print; print \"192.168.1.4 \myhost4\n\" if /^192.168.1.3/" tmp.txt
# type tmp.txt
192.168.1.1 myhost1
192.168.1.2 myhost2
192.168.1.3 myhost3
192.168.1.4 myhost4
192.168.1.10 myhost10

Under an hpux shell that should probably be:

# perl -pi -e 'print; print "192.168.1.4 \myhos4\n" if /^192.168.1.3/' tmp.txt

The "192.168.1.3" at the begin-of-line had better be unique enough.
Merijn's match is more exact, allowing for any whitespace between the number and name.
The problem with your solution may have the whitespace, but that's invisible (sic) in this forum presentation. They \s+ instead of spaces next time.

Cheers,
Hein.
H.Merijn Brand (procura
Honored Contributor

Re: perl question

Hein, that last command will print every line twice.

# perl -pi -e 'print; print "192.168.1.4 \myhos4\n" if /^192.168.1.3/' tmp.txt

should be either

# perl -pi -e '/^192.168.1.3/ and print "192.168.1.4 \myhos4\n"' tmp.txt

or

# perl -pi -e 'print "192.168.1.4 \myhos4\n" if /^192.168.1.3/' tmp.txt

or

# perl -ni -e 'print; print "192.168.1.4 \myhos4\n" if /^192.168.1.3/' tmp.txt

Guess which one I would prefer :)

AND they are not safe, as they also match lines that start with 192.168.1.33

Enjoy, Have FUN! H.Merijn
Enjoy, Have FUN! H.Merijn
H.Merijn Brand (procura
Honored Contributor

Re: perl question

for which all the first two insert the new line before the match and the third does what Hein suggested. Sorry for this.

Enjoy, Have FUN! H.Merijn
Enjoy, Have FUN! H.Merijn
limak
Occasional Advisor

Re: perl question

Procura,

Your first reply return this:
Substitution replacement not terminated at -e line 1.

perl -pi -e 'm/^192.168.1.4\s+myhost4/ and s/$/\n192.168.1.3\tmyhost3'/etc/hosts

Hein,

As procura said, your solution print 2 lines which create duplicate entries.

The only issue here as Procura mentioned it doesn't differentiate between the uniq names?

perl -ni -e 'print; print "192.168.1.4 \tmyhos4\n" if /^192.168.1.3/' /etc/hosts

cat /etc/hosts
192.168.1.1 myhost1
192.168.1.2 myhost2
192.168.1.3 myhost3
192.168.1.4 myhos4
192.168.1.10 myhost10
192.168.1.33 myhost33
192.168.1.4 myhos4
192.168.1.37 myhost37
192.168.1.4 myhos4

Any ideas?


H.Merijn Brand (procura
Honored Contributor

Re: perl question

perl -pi -e 'm/^192.168.1.4\s+myhost4/ and s/$/\n192.168.1.3\tmyhost3/' /etc/hosts

formatting isn't ITRC's best point.
trailing slash was missing after myhost3

Enjoy, Have FUN! H.Merijn
Enjoy, Have FUN! H.Merijn
H.Merijn Brand (procura
Honored Contributor
Solution

Re: perl question

Second problem: anchor

perl -ni -e 'print; print "192.168.1.4 \tmyhos4\n" if /^192.168.1.3\b/' /etc/hosts

Enjoy, Have FUN! H.Merijn
Enjoy, Have FUN! H.Merijn
limak
Occasional Advisor

Re: perl question

Procura,

I did add "/" before I post my last reply but nothing happened? Have you tried it yourself?
perl -pi -e 'm/^192.168.1.4\s+myhost4/ and s/$/\n192.168.1.3\tmyhost3/' /etc/hosts


This one worked like a charm!
perl -ni -e 'print; print "192.168.1.4 \tmyhos4\n" if /^192.168.1.3\b/' /etc/hosts


Can this be done with AWK and SED?

Where do you go to find these flags? any links for quick reference guide will be appreciated!


Hein van den Heuvel
Honored Contributor

Re: perl question


>> Hein,
>> As procura said, your solution print 2 lines which create duplicate entries.

My mistake, I somehow left a -p (which Prints $_ after each input iteration) on the line instead of the -n (which just loops over the input).

>> The only issue here as Procura mentioned >> it doesn't differentiate between the uniq names?

Yeah, I should reply ín a hurry'. To catch .3 being different from .33 the search pattern needs to be extended with something, anthying. I'd suggest simply using whitespace ( \s ) but many other options exists, like a word boundary ( \b ) or a non-digit ( \D ).
I would recommend against just using a simple space, because the file might legitemately have a tab as whitespace and you would not 'see' the difference.
In fact, this may well have been the original problem. Use ascii dump to test that: # grep "168.4" /etc/hosts | od -a

Anyway ... the fixed up command then becomes (again untested. Sorry) ...

perl -ni -e 'print; print "192.168.1.4 \tmyhos4\n" if /^192.168.1.3\s+/' /etc/hosts

Cheers,
Hein.



James R. Ferguson
Acclaimed Contributor

Re: perl question

Hi:

You asked Merijun & Hein where you would find documentation for the various flags that control Perl's behavior.

Complete documentation should be available with your own Perl installation. See 'perlrun' for a discussion of Perl's flags:

http://perldoc.perl.org/perlrun.html

More generally, for the most current release:

http://perldoc.perl.org/

Regards!

...JRF...
James R. Ferguson
Acclaimed Contributor

Re: perl question

Hi (again):

...with an apology to Merijn ...for misspelling his name. I can't type today :-))

Regards!

...JRF...
limak
Occasional Advisor

Re: perl question

You guys are really good!

Hein,
You got it! I tested it and it worked fine.

The white spaces made more sense as I went through the link James posted.


James,

So if I'm going to include of perl lines in a shell script, I would specify the switches "#!" like this as per the link?
#!/bin/sh -- # -*- perl -*- -p

That means perl will be executed when it's only found by the shell script. Did I understood that correctly?

I promise to assign points at the end. It's just getting more interesting!
H.Merijn Brand (procura
Honored Contributor

Re: perl question

Never seen that syntax

#!/bin/sh -- # -*- perl -*- -p

But, once you get the hack of scripting in perl, you don't call perl from sh scripts, but write perl scripts.

To translate your working line

perl -ni -e 'print; print "192.168.1.4 \tmyhos4\n" if /^192.168.1.3\b/' /etc/hosts

to a perl script
--8<---
#!/opt/perl/bin/perl

use strict;
use warnings;

open my $f_hosts, "< /etc/hosts" or die "/etc/hosts: $!";
my @hosts = <$f_hosts>;
close $f_hosts;
@hosts or die "/etc/hosts did not return me any lines";

open STDOUT, "> /etc/hosts" or die "/etc/host: $!\nprevious content:\n@hosts";
for (@hosts) {
print;
m/^192.168.1.3\b/ and print "192.168.1.4 \tmyhos4\n";
}
close STDOUT;
-->8---

Enjoy, Have FUN! H.Merijn [ who hopes to have demonstrated the strength of perl's commandline options ]
Enjoy, Have FUN! H.Merijn
limak
Occasional Advisor

Re: perl question

Procura,


Can the same perl line be translated into awk and sed?

Can you post good links with simple descriptions and examples for awk and sed?



H.Merijn Brand (procura
Honored Contributor

Re: perl question

my awk/sed foo is diminishing, as perl is all I need.

Perl supports translation the other way round, which in fact was quite helpful when I learned perl.

# a2p
# s2p

are the awk2perl and sed2perl translators.
once you start writing scripts in perl, there is most likely no way back to awk and/or sed, as the richness of features of perl makes sed and awk want to hide behind some trees. That does by no means make me say awk/sed is bad. I use those myself still quite often, but not in script form, but only from the command line, or in shell scripts.

For every problem unix has the right tool, and though perl can fit almost any problem, it is by no means the best tool for every problem. (though for me, knowing also about the darker corners, it comes very close).


NAME
a2p - Awk to Perl translator

SYNOPSIS
a2p [options] [filename]

DESCRIPTION
A2p takes an awk script specified on the command line (or from standard
input) and produces a comparable perl script on the standard output.


NAME
psed - a stream editor

SYNOPSIS
psed [-an] script [file ...]
psed [-an] [-e script] [-f script-file] [file ...]

s2p [-an] [-e script] [-f script-file]

DESCRIPTION
A stream editor reads the input stream consisting of the specified
files (or standard input, if none are given), processes is line by line
by applying a script consisting of edit commands, and writes resulting
lines to standard output. The filename `"-"' may be used to read stanâ
dard input.

The edit script is composed from arguments of -e options and
script-files, in the given order. A single script argument may be specâ
ified as the first parameter.

If this program is invoked with the name s2p, it will act as a sed-to-
Perl translator. See "sed Script Translation".


For the above, I would say that the awk solution would be something like

# awk '{print}/^192.168.1.4[ \t]/{print "192.168.1.4 myhost4"}' /etc/hosts

depending on the shell and your version/release of (GNU)awk, \t might not be recognized in the character class and should be replaced with a literal TAB character, often entered as Control-V TAB.

Enjoy, Have FUN! H.Merijn
Enjoy, Have FUN! H.Merijn
limak
Occasional Advisor

Re: perl question

Procura,

Few changes in awk. The TAB in the first one seem to work like whitespaces?
So I left it there and added \t in the second pattern.

This worked just fine.

awk '{print}/^192.168.1.3\t/{print "192.168.1.4\tmyhost4"}' /etc/hosts > /etc/hosts.tmp;cp /etc/hosts.tmp /etc/hosts


Is this book good to start with PERL?
http://www.oreilly.com/catalog/pperl3/

It looks like it's possible to compile your code in perl?

Arunvijai_4
Honored Contributor

Re: perl question

Is this book good to start with PERL?
http://www.oreilly.com/catalog/pperl3/

Here is a complete set,

http://unix.org.ua/orelly/perl/prog3/index.htm

-Arun
"A ship in the harbor is safe, but that is not what ships are built for"
limak
Occasional Advisor

Re: perl question

LOL!