Perl and hosts file mapping question? - perl

I have a hosts file that looks like this:
10.10.10.1 myserver1 myserver1alias
10.10.10.2 myserver2 myserver2alias
I'm looking for a way using perl to pass in an argument of myserver1 and have it return myserver1alias, likewise if I pass in myserver2 it should return myserver2alias. Any suggestions?

From the command line:
$ perl -lane 'print $F[-1] if $F[1] eq "myserver1"' /etc/hosts

while(<>){
if (/myserver1/){
#s = split /myserver1/,$_,2;
print $s[-1];
}
}

The quick-and-dirty way is:
perl -nE 'say $1 if /myserver1\s+(\w+)$/' path/to/hostfile
You might need to do queries similar to this from time to time, so you could probably make a reusable chunk of code to do this for you. Something like:
#!/usr/bin/perl
use strict;
use warnings;
use 5.10;
use HostFileParser;
my $host = HostFileParser->parse("path/to/hostfile")
my $server = $host->find(server => "myserver1")
say $server->alias;
Of course, I'm not going to "give you teh codez" for all of that. ;)
(These answers assume Perl 5.10, but if you don't have it the changes are just say $x => print "$x\n", or sub say { print "#_\n" }.)

Related

Perl parameters passing with special characters

This is a pure Perl parameters passing issue. I cannot use Get::Opt as it is not installed on every machine.
I need to pass parameters with spaces and other special chars sometimes. Three scripts to demo the process. Is there a better way to do this?
[gliang#www stackoverflow]$ perl parameter_wrapper.pl
prep.pl #<5> parameters
prep_v2.pl #<5> parameters
<aaa_777-1>
<bbb-6666-2>
<Incomplete QA>
<-reason>
<too long, mail me at ben#example.com :)>
cat parameter_wrapper.pl
#!/usr/bin/perl -w
use strict;
# call prep.pl with 5 parameters
my $cmd = "./prep.pl aaa_777-1 bbb-6666-2 'Incomplete QA' -reason 'too long, mail me at ben\#example.com :)\n'";
system($cmd);
cat prep.pl
#!/usr/bin/perl -w
use strict;
my #parameters = #ARGV;
my $count = scalar(#parameters);
my #parameters_new = wrap_parameters(#parameters);
my $cmd = "./prep_v2.pl #parameters_new";
print "prep.pl #<$count> parameters\n";
system($cmd);
sub wrap_parameters {
my #parameters = #_;
my #parameters_new;
foreach my $var(#parameters) {
$var = quotemeta($var);
push(#parameters_new, $var);
}
return #parameters_new;
}
cat prep_v2.pl
#!/usr/bin/perl -w
use strict;
my #parameters = #ARGV;
my $count = scalar(#parameters);
print "prep_v2.pl #<$count> parameters\n";
foreach my $var (#parameters) {
#print "<$var>\n";
}
Getopt::Long has been part of the Perl core since Perl 5 was first released in 1994. Are you sure it's not available on the machines you're looking to deploy on? In your comment you refer to it as "Get::Opt", so could you have made a mistake while checking the machines?

Pass a hash object from a perl script to through bsub (LSF)

This is an extension to my older question: Pass a hash object from one perl script to another using system. #Sobrique answered my question there.
Now, I want to know if I can pass an hash object to another perl script in the same way as my question above but using bsub.
wrapper script: script1.pl
use strict;
use warnings;
use Storable qw ( freeze );
use MIME::Base64;
my %test_hash = (
"fish" => "paste",
"apples" => "pears"
);
my $frozen = encode_base64 freeze( \%test_hash );
my ${string} = 'sample1';
# instead of just using system like this
# system("perl", "some_other_script.pl", $frozen);
# I want to use something like this:
system('bsub','-J',${string},'-o','${string}.out','-e','${string}.err','perl','some_other_script.pl',$frozen);
some_other_script.pl
use strict;
use warnings;
use Storable qw ( thaw );
use Data::Dumper;
use MIME::Base64;
# should read the imported hash correctly and print it out
my ($imported_scalar) = #ARGV;
print $imported_scalar;
my %param = %{ thaw (decode_base64 $imported_scalar ) };
print $param{'fish'};
print "\n";
How can I achieve this? Any help would be much appreciated.
Thanks!
This is really more a question about bsub than perl. Passing arguments via Base64 encoded parameters might do the trick, but actually if your purpose is passing data into the batch processing system, it might be worth using an input file:
If you have a look through the bsub manpage, you'll see:
-i input_file | -is input_file
That's probably a better way of handing 'input' to your batch job.

Search and replace in Perl for particular word

I have a huge file which consists of similar lines below , with different clocks:
cmd -quiet [get_ports p1] ref_clocks "cudtclk_sp cudtclk"
cmd -quiet [get_ports p2] clock "cu2xdtclk_sp cu2xdtclk"
And I need to replace cudtclk with some other name like cdtclk whenever I have ref_clocks in my file, globally.
I have written following code but it doesn't seem to be working.
#!/usr/bin/perl
use strict;
use warnings;
sub clock_change
{       # Get the subroutine's argument.
my $arg = shift;
# Hash of stuff we want to replace.
my %replace = (
"cudtclk" => "cdtclk",
);
# See if there's a replacement for the given text.
my $text = $replace{$arg};
if(defined($text)) {
return $text;
}
return $arg;
}
open PAR, "<file name>";
while(<PAR>) {
$_ =~ s/\S+\s\S+\s\S+\s\S+\sref_clocks\s+(\S+\s+\S+)/clock_change($1)/eig;
print $_;   ##print it to some file later.
}
"And I need to replace cudtclk with some other name like cdtclk"
perl -pe 's/\bcudtclk\b/cdtclk/' thefile > newfile
"whenever I have ref_clocks"
perl -pe 's/\bcudtclk\b/cdtclk/ if /\bref_clocks\b/' thefile > newfile
Alternatively:
# saves original file as file.bak
perl -i.bak -pe 's/\bcudtclk\b/cdtclk/ if /\bref_clocks\b/' file
Tighten to suit your data, as necessary.
Although the substitution seems like unnecessarily complex, you can fix it with something similar to:
$_ =~ s/(ref_clocks\s+")([^_]+)_sp(\s+)\2/
$1.clock_change($2)."_sp$3".clock_change($2)/eig;

Unquoting a String in Perl

I have a subroutine in Perl sub findfiles , I have to pass a quoted value "*/*" as input parameter since it complains without quoting ,on the other hand in my subroutine I needed it to be unquoted (may be!)The problem is when I print the value to check ,I don't see any quote,or any thing but may be there are some special hidden character or something I don't know ? My codes work properly when I use */*directly but not when I pass it as as an input parameter
Do you have any idea?
sub findfiles {
$dirname=$_[0];
my #temp = grep {-f} <$dirname>;
print #temp;
}
&findfiles("*/*"); doesnot work
but
sub findfiles {
$dirname=$_[0];
my #temp = grep {-f} <*/*>;
print #temp;
}
does its job
With your updated code, I can see where your error lies. While
my #temp = grep {-f} <*/*>;
Works as a glob
my #temp = grep {-f} <$dirname>;
Is interpreted as a readline() on the file handle $dirname.
If you want to avoid ambiguity you can use the function for glob:
my #temp = grep -f, glob $dirname;
You might also be interested in using File::Find, which finds files recursively.
NOTE: This problem could have been avoided if you had warnings turned on. As a rule of thumb, coding in perl without using
use strict;
use warnings;
...is a very bad idea. These two pragmas will help you identify problems with your code.
The problem is when I print the value to check ,I don't see any quote
$test="*/*"
^string delimiter
^^^string
^string delimiter
When you print a string (be it from a string literal, a scalar or whatever) you print the string.
The delimiters don't get printed. They just tell perl where the edges of the data are.
Do you know about File::Find?
use File::Find ();
File::Find::find( sub { say $File::Find::name if -f; } => $my_root );
Or what about File::Find::Rule (see file)?
say foreach File::Find::Rule->file->in( $my_root );

How can I remove the timestamp from a filename in Perl?

I have a file which has a line in it as:
/hosting/logs/U01-ecom-SIT01/CU01-DC05-IFIO_SIT01_NU01-nc3sz1ecmas11/waslogs/SystemOut_10.01.21_16.54.18.log`
I need a script which would read this line and remove the time stamp from it, that is:
10.01.21_16.54.18
The script should print the filename without the timestamp and holding the full path, that is:
/hosting/logs/U01-ecom-SIT01/CU01-DC05-IFIO_SIT01_NU01-nc3sz1ecmas11/waslogs/SystemOut.log`
Please help as I'm unable to pattern match and output the file path without the timestamp.
echo "/hosting/logs/U01-ecom-SIT01/CU01-DC05-IFIO_SIT01_NU01-nc3sz1ecmas11/waslogs/SystemOut_10.01.21_16.54.18.log" |
perl -pe "s/_\d\d\.\d\d\.\d\d_\d\d\.\d\d\.\d\d//;"
$ perl -e 's{_\d{2}\.\d{2}.\d{2}_\d{2}\.\d{2}.\d{2}}{} and print for #ARGV' /hosting/logs/U01-ecom-SIT01/CU01-DC05-IFIO_SIT01_NU01-nc3sz1ecmas11/waslogs/SystemOut_10.01.21_16.54.18.log
Path shortened to prevent scrolling:
$ cat paths
CU01-DC05-IFIO_SIT01_NU01-nc3sz1ecmas11/waslogs/SystemOut_10.01.21_16.54.18.log
$ perl -pe 's/(_(\d\d(\.\d\d){2})){2}\.log$/.log/' paths
CU01-DC05-IFIO_SIT01_NU01-nc3sz1ecmas11/waslogs/SystemOut.log
The timestamp is made up of 2 sequences that look like _##.##.##. The subsequences end with 2 sequences of .##. These are the roles of the {2} quantifiers.
while(<>){
#s = split /\// ;
$fullpath=join("/",splice #s , 0, $#s);
#a = split /[_.]/ ,$s[-1];
$newfile="$fullpath/$a[0].$a[-1]";
print $newfile."\n";
}
You can use the following coding
use strict;
use warnings;
my $var; $var=/hosting/logs/U01-ecom-SIT01/CU01-DC05-IFIO_SIT01_NU01-nc3sz1ecmas11/waslogs/SystemOut_10.01.21_16.54.18.log";
$var=~s/_\d\d\.\d\d\.\d\d//g;
# $var=~s/_10\.01\.21_16\.54\.18//g; # You can use this way also
print "$var\n";