I got a pretty strange problem with my perl-script. I really have no idea, what's happening there, maybe you will see it...
My script uses Net::SSH::Perl to connect to a host-machine via SSH. After that I head -20 on a config.ini and search for some pattern (a version number).
After I print the version number i cat some other file which is approximately 700 lines long.
What's happening now is, that instead of printing the version-number, the script prints the whole 700-line-file. Unless I addprint "\n"x10; directly behind the version-print.
This behaviour doesn't make any sense to me, but I'm sure one of you will be smarter than me and know the answer :)
Below the script:
1 #!/usr/local/bin/perl -w
2 use lib './';
3 use strict;
4
5 use GetVersions;
6 use Net::SSH::Perl;
7
8
9 my $ssh = Net::SSH::Perl->new(
10 'host',
11 identity_files => ['~/.ssh/id_rsa']
12 );
13
14 $ssh->login('user');
15
16 my $ver_regex = '^psadm\.version\s*=\s*rel_(.+)$';
17
18 my ($file, $err, $exit) = $ssh->cmd('head -20 /config.ini');
19 my $version = $file =~ /$ver_regex/m;
20 print "version: $version\n",
21 #print "\n"x10;
22 ($file, $err, $exit) = $ssh->cmd('cat /application.ini');
This should probably be a semicolon
print "version: $version\n",
^
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I think it won't be a straightforward thing to solve, but here it is. I have a file in the following format:
"2004-04-19 12:25:00" 44 44
"2004-04-19 12:26:30" 36 36
"2004-04-19 12:27:15" 34 34
and I need a file with exact same content, except that the first row of the first column is 0, and remaining values of the first column are times in minutes since time 0 (since first time). Times should be rounded 3 digit after decimal (dot), like this:
0.000 44 44
1.500 36 36
2.250 34 34
I am as disappointed as the others who downvoted your question with your reluctance to even attempt to do this for yourself before asking for free help. If you always do this then you will never learn the language and will always have to rely on other people to do it for you. However, I would prefer that you got your solution from Stack Overflow, as I am sure you will only go elsewhere and ask the same question
This will do as you ask. It expects the path to the input file as a parameter on the command line, and sends the output to STDOUT
To write the output to a file you would redirect it on the command line, like this
$perl fractional_minutes.pl mydata.txt > mydata_new.txt
and if you want to write back to the same file then you will need to use Perl's in-place option, like this
$perl -i.bak fractional_minutes.pl mydata.txt
which will save the old file as mydata.txt.bak
use strict;
use warnings;
use Time::Piece;
use Time::Seconds qw/ ONE_MINUTE /;
my $t0;
while ( <> ) {
s{^"([^"]*)"}{
my $t = Time::Piece->strptime($1, '%Y-%m-%d %H:%M:%S');
$t0 = $t if not defined $t0;
sprintf('%.3f', ($t - $t0) / ONE_MINUTE);
}e;
print;
}
output
0.000 44 44
1.500 36 36
2.250 34 34
With GNU awk for mktime() and gensub():
$ cat tst.awk
BEGIN { FS="\"" }
{ mins=mktime(gensub(/[-:]/," ","g",$2)) / 60 }
NR==1 { startMins=mins }
{ printf "%.3f%s\n", (mins-startMins), $3 }
$ awk -f tst.awk file
0.000 44 44
1.500 36 36
2.250 34 34
Here is a solution that uses Time::Moment:
#!/usr/bin/perl
use strict;
use warnings;
use Time::Moment;
my #times = map {
Time::Moment->from_string($_ . 'Z', lenient => 1)
} ('2004-04-19 12:25:00',
'2004-04-19 12:26:30',
'2004-04-19 12:27:15');
my $first = $times[0];
foreach my $time (#times) {
printf "%.3f\n", ($time->rd - $first->rd) / (1/60/24);
}
Output:
0.000
1.500
2.250
I am debugging this script at work - the boss says that is used to work on Solaris, but since they switched over to linux, it stopped working. I had to rewrite it with strict and warnings .
When I run it I get error:
Undefined subroutine &Logging::openLog called at /path/to/script line 27
here is script (well part of it)
1 #!/usr/local/bin/perl
2
3 unshift #INC, "/production/fo/lib";
4 use strict;
5 use warnings;
6 use Sys::Hostname;
7 use Getopt::Long qw(:config bundling auto_version);
8 use File::Path;
9
10 require "dbconfig2.pl";
11 require "logging2.pl";
12 require "hpov.pl";
13
14 # global variables
15 my $parseDate = "";
16 my #fileList = "";
17 my #transList = "";
18 my $mLogDate = "";
19 my $lHost = hostname;
20 my $corefiles_dir="/production/log/corefiles";
21 my $default_Threshold=90;
22
23 # do stuff
24
25 parseOptions();
26 Dbconfig::readconfigFile("$config");
27 Logging::openLog("$Dbconfig::prefs{logFile}","overwrite");
28 # msglog actions TODO logs, compress only, data files
29 my $check_shdw=`ls -l /etc/motd | awk '{print \$11}' | grep 'motd.shdw'`; #Check if hostname is shadow
30 $check_shdw =~ y/\n//d; #remove new line if any
31 if ( $check_shdw eq "motd.shdw" )
32 {
33 Logging::printLog("INFO","Enviroment is Shadow, triggering core files compressing");
34 if (is_folder_empty($corefiles_dir)) {
35 print "Corefile Directory is EMPTY......! \n";
36 }
37 else {
38 gzip_corefiles() ; #Execute compress core files
39 }
40 }
41
The script uses require statements to I guess call upon the routines that the script creator built.
For the purpsoe of this script - the dbconfig just slurps in a config file and breaks them down into values.
like the "$Dbconfig::prefs{logFile}" equals a logfile location /prod/logs/script.log - that's it.
#!/usr/local/bin/perl
package Dbconfig;
#use warnings;
use DBI;
use DBD::Oracle;
%prefs = "";
#$dbPrefs = "";
$raiseError = 0;
%startupItem = "";
# readconfigFile(file) - read in a configuration file.
sub readconfigFile {
my $file = shift;
if ( ! -e $file ) {
$errorTxt = "Error: $file does not exist.\n";
$raiseError = 1;
}
# read in the cfg variables
open(CFGFILE,"<","$file") or die "Cannot open $file for reading: $!\n";
while(<CFGFILE>) {
chomp; # kill newlines
s/#.*//; # ignore comments
s/^\s+//; # ignore leading whitespace
s/\s+$//; # ignore trailing whitespace
next unless length;
my($var,$value) = split(/\s*=\s*/, $_, 2);
$prefs{$var} = $value;
}
close(CFGFILE);
}
Then there is this logging package. In line 27 of the script (where the error comes in) i see an "overwrite" invocation, but don't see anything referenceing overwrite in the logging.pl package - but not really sure if it matters. the parent script does not seem to write to any log file. I am not even sure if the filehandle LOGFILE is gtting created.
#!/usr/local/bin/perl
package Logging;
use File::Copy;
use warnings;
use strict;
my $timestamp = "";
my $filestamp = "";
# openLog(logfile name) - opens a log file
sub openLog {
my $file = shift;
my $rotate = shift;
# force a rotation if it exists.
if ( -e $file && $rotate eq "rotate" ) {
print "Warning: $file exists. Rotating.\n";
rotateLog($file);
}
getTime();
open(LOGFILE,">","$file") or warn "Error: Cannot open $file for writing: $!\n";
print LOGFILE "[$timestamp] - Normal - Opening log for $file.\n";
}
# rotateLog(log file) - rotate a log.
sub rotateLog {
my $file = shift;
getTime();
openLog("$file");
print LOGFILE "[$timestamp] - Warning - Rotating $file to $file.$filestamp.log";
closeLog($file);
move($file,$file-"$filestamp.log");
openLog($file);
}
time() - grab timestamp for the log.
sub getTime {
undef $timestamp;
undef $filestamp;
($sec,$min,$hour,$mday,$mon,$year) = (localtime(time))[0,1,2,3,4,5];
$sec = sprintf("%02d",$sec);
$min = sprintf("%02d",$min);
$hour = sprintf("%02d",$hour);
$mday = sprintf("%02d",$mday);
$year = sprintf("%04d",$year +1900);
$mon = sprintf("%02d",$mon +1);
$timestamp = "$mon-$mday-$year $hour:$min:$sec";
$filestamp = "$year$mon$mday$hour$min$sec";
}
just wondering - is there a problem with logging.pl calling something from dbconfig.pl in line 27? Like can one module call a value fron another module? besides using strict and warnings, and alot of print statements I do not know what my next debugging
step is. I have not idea how to check and see that the LOGFILE filehandle is getting created - if it does not error out, I can only suppose that it is. Like is there something extra I have to do to get the modules talking to each other?
I am not a scripting king - just the only guy in my row who can even begin to understand this stuff.
Not sure if this will effect things but ....
1) Packages need to return true, normal procedure is to end the file with the line:
1;
to ensure that.
2) Theres a comment in the logger package without the leading # which would cause compilation failure:
time() - grab timestamp for the log.
3) This line:
unshift #INC, "/production/fo/lib";
is adding the directory to search path for modules, make sure your logging2.pl file is actually in that location (it propably is otherwise you would get different errors, but worth a double check)
That looks all OK then.
For some reason although require "logging2.pl" works (there'd be an error if not) the sub-routines in it aren't loaded and available. Unlike the load of DBconfig2.pl which works OK (otherwise the call to Dbconfig::readconfigFile() would fail first).
Only difference I can see is the leading space on the package command in Logging2.pl, don't think that would matter though.
Could try calling openLog without the package prefix (Logging::) to see if its been loading into main from some reason and print the contents of %INC after the require statements to make sure its been loaded correctly?
Need help in merging/concatenating /combining /binding etc
I have several ascii files each defining one variable which I have converted to a single column array
I have such columnised data for many variables ,so I need to perform a column bind like R does and make it one single file.
I can do the same in R but there are too many files. Being able to do it with one single code will help save a lot of time.
Using the following code ,new to perl and need help with this.
#filenames = ("file1.txt","file2.txt");
open F2, ">file_combined.txt" or die;
for($j = 0; $j< scalar #filenames;$j++){
open F1, $filenames[$j] or die;
for($i=1;$i<=6;$i++){$line=<F1>;}
while($line=<F1>){
chomp $line;
#spl = split '\s+', $line;
for($i=0;$i<scalar #spl;$i++){
print F2 "$spl[$i]\n";
paste "file_bio1.txt","file_bio2.txt"> file_combined.txt;
}
}
close F1;
}
Input files here are Ascii text files of a raster.They look like this
32 12 34 21 32 21 22 23
12 21 32 43 21 32 21 12
The above mentioned code without the paste syntax converts these files into a single column
32
12
34
21
32
21
22
23
12
21
32
43
21
32
21
12
The output should look like this
12 21 32
32 23 23
32 21 32
12 34 12
43 32 32
32 23 23
32 34 21
21 32 23
Each column represents a different ascii file.
I need around 15 such ascii files into one dataframe.I can do the same in R but it consumes a lot of time as the number of files and regions of interest are too many and the files are a bit large too.
Let's step through what you have...
# files you want to open for reading..
#filenames = ("file1.txt","file2.txt");
# I would use the 3 arg lexical scoped open
# I think you want to open this for 'append' as well
# open($fh, ">>", "file_combined.txt") or die "cannot open";
open F2, ">file_combined.txt" or die;
# #filenames is best thought as a 'list'
# for my $file (#filenames) {
for($j = 0; $j< scalar #filenames;$j++){
# see above example of 'open'
# - $filenames[$j] + $file
open F1, $filenames[$j] or die;
# what are you trying to do here? You're overriding
# $line in the next 'while loop'
for($i=1;$i<=6;$i++){$line=<F1>;}
# while(<$fh1>) {
while($line=<F1>){
chomp $line;
# #spl is short for split?
# give '#spl' list a meaningful name
#spl = split '\s+', $line;
# again, #spl is a list...
# for my $word (#spl) {
for($i=0;$i<scalar #spl;$i++){
# this whole block is a bit confusing.
# 'F2' is 'file_combined.txt'. Then you try and merge
# ( and overwrite the file) with the paste afterwards...
print F2 "$spl[$i]\n";
# is this a 'system call'?
# Missing 'backticks' or 'system'
paste "file_bio1.txt","file_bio2.txt"> file_combined.txt;
}
}
# close $fh1
close F1;
}
# I'm assuming there's a 'close F2' somewhere here..
It looks like you're trying to do this:
#filenames = ("file1.txt","file2.txt");
$oufile = "combined_text.txt";
`paste $filenames[0] $filenames[1] > $outfile`;
I want to get the output of a command into an array — like this:
my #output = `$cmd`;
but it seems that the output from the command does not go into the #output array.
Any idea where it does go?
This simple script works for me:
#!/usr/bin/env perl
use strict;
use warnings;
my $cmd = "ls";
my #output = `$cmd`;
chomp #output;
foreach my $line (#output)
{
print "<<$line>>\n";
}
It produced the output (except for the triple dots):
$ perl xx.pl
<<args>>
<<args.c>>
<<args.dSYM>>
<<atob.c>>
<<bp.pl>>
...
<<schwartz.pl>>
<<timer.c>>
<<timer.h>>
<<utf8reader.c>>
<<xx.pl>>
$
The output of command is split on line boundaries (by default, in list context). The chomp deletes the newlines in the array elements.
The (standard) output does go to that array:
david#cyberman:listing # cat > demo.pl
#!/usr/bin/perl
use strict;
use warnings;
use v5.14;
use Data::Dump qw/ddx/;
my #output = `ls -lh`;
ddx \#output;
david#cyberman:listing # touch a b c d
david#cyberman:listing # perl demo.pl
# demo.pl:8: [
# "total 8\n",
# "-rw-r--r-- 1 david staff 0B 5 Jun 12:15 a\n",
# "-rw-r--r-- 1 david staff 0B 5 Jun 12:15 b\n",
# "-rw-r--r-- 1 david staff 0B 5 Jun 12:15 c\n",
# "-rw-r--r-- 1 david staff 0B 5 Jun 12:15 d\n",
# "-rw-r--r-- 1 david staff 115B 5 Jun 12:15 demo.pl\n",
# ]
Enable automatic error checks:
require IPC::System::Simple;
use autodie qw(:all);
⋮
my #output = `$cmd`;
I want to output strings into eight columns, but I want to keep the spacing the same. I don't want to do it in HTML, but I am not sure how to do it normally. Example:
Something Something Something Something Something
Else Else Else Else Else
Another Another Another Another Another
The amount of rows will change daily, but the column number will always stay the same. What is the best way to do this?
printf
printf "%-11s %-11s %-11s %-11s %-11s %-11s %-11s %-11s\n",
$column1, $column2, ..., $column8;
Change "11" in the template to whatever value you need.
You could use Perl's format.
This is probably the "complicated" method that you don't understand, most likely because it gives you many options (left|center|right justification/padding, leading 0's, etc).
Perldoc Example:
Example:
format STDOUT =
#<<<<<< #|||||| #>>>>>>
"left", "middle", "right"
.
Output:
left middle right
Here's another tutorial.
Working Example: (Codepad)
#!/usr/bin/perl -w
use strict;
sub main{
my #arr = (['something1','something2','something3','something4','something5','something6','something7','something8']
,['else1' ,'else2' ,'else3' ,'else4' ,'else5' ,'else6' ,'else7' ,'else8' ]
,['another1' ,'another2' ,'another3' ,'another4' ,'another5' ,'another6' ,'another7' ,'another8' ]
);
for my $row (#arr) {
format STDOUT =
#<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<<
#$row
.
write;
}
}
main();
Here is a live example of Perl6::Form:
#!/usr/bin/perl
use Perl6::Form;
my #arr = (
[1..8],
[9..16],
[17..24],
);
foreach my $line (#arr) {
print form
"{<<<<<} "x8,
#{$line};
}
It will output:
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
I would look at formatting, but I would do it using Perl 6's (now Raku) Form.pm, which you can obtain as Perl6::Form for Perl 5.
The reason for this is that the format builtin has a number of drawbacks, such as having the format statically defined at compile time (i.e., building it dynamically can be painful and usually requires string eval), along with a whole list of other shortcomings, such as lack of useful field types (and you can't extend these in Perl 5).