Perl Concat String Truncates Beginning of Line - perl

I am running into a strange issue in perl that I can't seem to find an answer for.
I have a small script that will parse data from an external sorce (be it file, website, etc). Once the data has been parsed, it will then save it to a CSV file. However, the issue is when I am writing the file or printing to screen the data, it seems to be truncating the beginning of the string. I am using strict and warnings and I am not seeing any errors.
Here is an example:
print "Name: " . $name . "\n";
print "Type: " . $type. "\n";
print "Price: " . $price . "\n";
print "Count: " . $count . "\n";
It will return the following:
John
Blue
7.99
5
If I attempt to do it this way:
print "$name,$type,$price,$count\n";
I get the following as a result:
,7.99,5
I tried the following to see where the issue begins and get the following:
print "$name\n";
print "$name,$type\n";
print "$name,$type,$price\n";
print "$name,$type,$price,$count\n";
Results:
John
John,Blue
,7.99
,7.99,5
I am still learning perl, but can't seem to find out (maybe due to lack of knowledge) of what is causing this. I tried debugging the script, but I did not see any special character in the price variable that would cause this.

The string in $price ends with a Carriage Return. This is causing your terminal to move the cursor to the start of the line, causing the first two fields to be overwritten by the ones that follow.
You are probably reading a Windows text file on a unix box. Convert the file (using dos2unix, for example), or use s/\s+\z//; instead of chomp;.
If the CR made into the middle of a string, you could use s/\r//g;.

Per #Mat suggestion I ran the output through hexdump -C and found there was a carriage return (indicated by the hex value 0d). Using the code $price =~ s/\r//g; to remove the CR from the line of text fixed the problem.
Also, the input file was in Windows format not Unix, ran the command dos2unix to fix that.

Related

Perl - How to output all on one line

I'm new to PERL but have picked it up rather quickly as I work in C.
My question seems simple, but for the life of me I cant find a simple answer. Basically I want to print something on the same line as user input
Example
print "Please Enter Here: ";
my $input = <STDIN>;
chomp $input;
print " - You Entered: $input";
Output
Please Enter Here: 123
- You Entered: 123
This is undesired as I want all of this on one line in the terminal window. At the moment it prints the second string on the line below once the user has pressed the enter key. I guess what i'm going to need to do is something with STDIN like ignore the carriage return or newline but I'm not sure.
Desired Output
Please Enter Here: 123 - You Entered: 123
I don't know why this seems to be a complicated thing to google but I just haven't fathomed it, so any help would be appreciated.
Ta
Well, this is interesting...
First, you'd have to turn off terminal echoing, using something like IO::Stty. Once you do that, you could use getc. Note that the getc perldoc page has a sample program that could be used. You can loop until you get a \n character as input.
You can also try Term::ReadKey.
I have never done this myself. I'll have to give it a try, and if I succeed, I'll post the answer.
The Program
Ended up I already had Term::ReadKey installed:
#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);
use Term::ReadKey;
ReadMode 5; # Super Raw mode
my $string;
print "Please Enter Here: ";
while ( my $char = getc ) {
last if ord( $char ) < 32; # \r? \n? \l?
$string .= $char;
print "$char";
}
ReadMode 0;
say qq( - You entered "$string".);
I realized that, depending how the terminal is setup, it's hard to know exactly what is returned when you press <RETURN>. Therefore, I punted and look for any ASCII character that's before a space.
One more thing: I didn't handle what happens if the user hit a backspace, or other special characters. Instead, I simply punt which may not be what you want to do.
In the end I did:
"\033[1A\033[45C
It uses the code functions for line up and 45 indent and it works. Thanks for all the help though.

Perl reads only the last line of my file?

OK I have a file which is a list of over 5000 names, one line each;
the file is a txt file generated with microsoft excel.
The following code gave me an output of 1.
open FILEHANDLE, "< listname_FC2-3ss>0.txt";
chomp (my #genelist = <FILEHANDLE>);
close FILEHANDLE;
print "the number of item in the list is ";
print scalar #genelist;
I'm using a '10 macbook air, perl 5.12.I tried to output the list and its the last line of the file.
But I tried the code on a tiny version of 10 names which I extracted by hand myself and it worked perfectly fine, so i reckon it's got something to do with the delimiter?
Please help.
Ian
Try with
local $/ = "\r";
before file reading. It changes the input record separator to the "\r" character.

Use awk in Perl to parse everything between two strings

I have a huge pile of log files constantly being updated on HP-UX server.I have created the Perl code to find out the name of log file in which the string i'm using resides inside.
Perl gets the file name using split and passes it into a variable.Using the userinput i create the start and stop strings as two variables.Such as:
my $ssh = Net::OpenSSH->new($host, user => $user,
master_opts => [ -o => 'NumberOfPasswordPrompts=1',
-o => 'PreferredAuthentications=keyboard-interactive,password'],
login_handler => \&login_handler);
$ssh-> error and die "Unable to connect" . $ssh->error;
my $output=$ssh->capture("grep .$userinput1. /app/bea/user_projects/domains/granite/om_ni.log*");
my $array = (split ":", $output)[0];
print "$array"."\n";
[EDIT]: As you guys requested,above is the beginning of how the $array got filled in.Below is where the awk sequence starts:
my $a= "INFO - $userinput1";print $a;
my $b= "INFO - ProcessNode terminated... [$userinput1]";print $b;
Using the awk as part of ssh capture command,it will search through the whole log file and capture every line between the string $a and string $b,then get everything inside another array.Such as:
my $output2=$ssh->capture("awk -v i=$array '$a,$b' i");
Here $array is where the log file's full path is held and it work completely fine as a passing variable.
I tried using the awk without -v parameter as well,didn't matter at all.
[EDIT 2]:this is the result of print "$array"."\n";
/app/bea/user_projects/domains/granite/om_ni.log.2
When I run the perl script,I get the result:
INFO - 28B26AD1-E959-4F5F-BD89-A7A6E601BE18INFO - ProcessNode terminated... [28B26AD1-E959-4F5F-BD89-A7A6E601BE18] syntax error The source line is 1.
The error context is
INFO - 28B26AD1-E959-4F5F-BD89-A7A6E601BE18,INFO - ProcessNode >>> terminated. <<< .. [28B26AD1-E959-4F5F-BD89-A7A6E601BE18]
awk: Quitting
The source line is 1.
Error pointing at the "terminate" word somehow but even when I use escape characters all over the strings,it just doesn't care and returns the same error.
Any help on this issue is highly appreciated.Thanks a lot in advance.
While I don't really know awk, the way you are invoking it does not appear to be correct. Here is the manual for awk on HP-UX.
The part in single quotes ($a,$b) should be the program. However, you are passing it two text strings, which are not even quoted to separate them. This is not a valid awk program; hence the syntax error.
I think what you want is something like '/$a/, /$b/' for the program (but again, I am not an awk expert).
Also, you are setting the filename to variable i, then using i in the place of the filename when you invoke the command. I don't know why you are doing this, and I don't think it will even work to use a variable in the filename. Just use $array (which you should rename to something like $file for clarity) in the filename position.
So your whole command should look something like:
"awk '/$a/,/$b/' $file"
In this single command, you are dealing with three different tools: Perl, SSH, and awk. This is very hard to debug, because if there is a problem, it can be hard to tell where the problem is. It is essential that you break down the task into smaller parts in order to get something like this working.
In this case, that means that you should manually SSH into the server and play around with awk until you get the command right. Only when you are sure that you have the awk command right should you try incorporating it into Perl. It will be much easier if you break down the task in that way.

Confused about string terminator in Perl

I read several postings here about getting the error message -
can't find string terminator "" anywhere before EOF ...
can't find string terminator "'" anywhere before EOF ...
I don't think I really understand it, although the take-home message is not to use single quotes.
So okay, I will try NOT to use single quotes. But still, if possible, could someone help me understand the differences between the two scripts, in terms of how Perl sees them differently
#!/usr/bin/perl -w
#backwhacking
print "c:\\WINNT\\Profiles\\\n";
print 'c:\WINNT\Profiles\ ', "\n";
#!/usr/bin/perl -w
#backwhacking
print "c:\\WINNT\\Profiles\\\n";
print 'c:\WINNT\Profiles\', "\n";
The first script runs fine with the output
c:\WINNT\Profiles
c:\WINNT\Profiles
whereas the second script gave me the same error code about not able to find script terminator "'"
And is there any "reason" why Perl programming needs to distinguish between with or without a space with single quotes? Sorry, but it seems somewhat trivial to a non-computer science person.
' style quotes use backslash to escape ' character.
So: print '\''; will print ' character, and not \' string.
when you print 'whatever\ ' - it will print >whatever < - with space at the end. But if you do:
print 'whatever \'
this is not terminated string, because the backslash escapes '. So the following , "\n"; are treated as part of '' string.

Why is Perl's chomp affecting the output of my print?

It's been a couple months since I've been Perling, but I'm totally stuck on why this is happening...
I'm on OSX, if it matters.
I'm trying to transform lines in a file like
08/03/2011 01:00 PDT,1.11
into stdout lines like
XXX, 20120803, 0100, KWH, 0.2809, A, YYY
Since I'm reading a file, I want to chomp after each line is read in. However, when I chomp, I find my printing gets all messed up. When I don't chomp the printing is fine (except for the extra newline...). What's going on here?
while(<SOURCE>) {
chomp;
my #tokens = split(' |,'); # #tokens now [08/03/2011, 01:00, PDT, 1.11]
my $converted_date = convertDate($tokens[0]);
my $converted_time = convertTime($tokens[1]);
print<<EOF;
$XXX, $converted_date, $converted_time, KWH, $tokens[3], A, YYY
EOF
}
With the chomp call in there, the output is all mixed up:
, A, YYY10803, 0100, KWH, 1.11
Without the chomp call in there, it's at least printing in the right order, but with the extra new line:
XXX, 20110803, 0100, KWH, 1.11
, A, YYY
Notice that with the chomp in there, it's like it overwrites the newline "on top of" the first line. I've added the $|=1; autoflush, but don't know what else to do here.
Thoughts? And thanks in advance....
The lines of your input ends with CR LF. You're removing the LF only. A simple solution is to use the following instead of chomp:
s/\s+\z//;
You could also use the dos2unix command line tool to convert the files before passing them to Perl.
The problem is that you have DOS line-endings and are running on a Unix build of Perl.
One solution to this is to use PerlIO::eol. You may have to install it but there is no need for a use line in the program.
Then you can write
binmode ':raw:eol(LF)', $filehandle;
after which, regardless of the format or source of the file, the lines read will be terminated with the standard "\n".