Perl print device list - perl

I have one file which contain device name and it's an output from shell script depending upon region.So region is variable which can be change....e.g
devicelist=device.region
Now I want to add this device list into email body. For sending email I am using perl script and I have tried below method but its not working...
my $file = "$ENV{devicelist}";
open my $fh, '<', $file;
print while (<$fh>);
I am getting this message as : GLOB(0x11aeea8)
Perl script ....
my $file = "/tmp/devicelist";open my $fh, '<', $file;print while (<$fh>);
$logger->debug("$logid >> Device names is $deviceinfo");
$smtp->datasend("Customer Name : $custname\n\n");
$smtp->datasend("Site Location : $sitename\n\n");
$smtp->datasend("Region : $region\n\n");
my $file = "/tmp/devicelist";
open my $fh, '<', $file;
print while (<$fh>);
$smtp->datasend("Device Info : $deviceinfo\n\n"); 1st way
$smtp->datasend("Device Info perl : $fh\n\n"); 2nd way
This request is dealing where i am sending email when there are more than 10 device down and I want to present those 10 devices names. Other information are showing perfectly fine as those are single value stored in variable like region,state ..etc...
Thanks

All you need is to change
print while (<$fh>);
to
$smtp->datasend($_) while (<$fh>);

Are you asking how to load a file's content into a variable?
my $file; { local $/; $file = <$fh>; }

Printing by default goes to standard out, and not to the same place where $smtp->data send() is sending string parameters.
I think you just want to re-write your while loop and direct the output correctly; so...
print while (<$fh>); #is basically saying:
while (<$fh>) {
print;
} #but in your smtp block, you don't want to be printing, so write
foreach $fileline (<$fh>) { $smtp->datasend($fileline); }
Once you try that, if it's working and therefore this explains what was wrong, then look into slurping the whole file in at once with something like:
my $file = "/tmp/devicelist";
open my $fh, '<', $file;
my $filecontents; { local $/; $filecontents = <$fh>; }
$smtp->datasend($filecontents);
Other than that, when you say:
print while (<$fh>);
I am getting this message as : GLOB(0x11aeea8)
Do you mean, you didn't want to get GLOB(0x11aeea8) or that this is correct output?
If it's the former, I think that's because you wanted to write something like:
while (<$fh>) {print $_;}

Related

Writing to a file inside if statement not working in Perl

I've looked around here a bit and found similar questions but not exactly. If there is one, I apologize and please point me to it.
I have the following code. I'm trying to create a csv file of simply an ID pulled from a filename and the filename itself. This is the ENTIRE script.
use strict;
use warnings;
use File::Find;
find( \&findAllFiles, '.');
exit;
sub findAllFiles {
my #fp1;
my #fp2;
my $patId;
my $filename;
my $testvar = "hello again";
$filename = $File::Find::name;
if ($filename =~ /\.pdf$/) {
open (my $fh, '>', 'filenames.csv') or die "Failed to open - $!\n";
print $fh "starting...$testvar\n" or die "Failed to print to file - $!\n";
#fp1 = split('/', $filename);
#fp2 = split('_', $fp1[-1]);
$patId = $fp2[-1];
$patId =~ s/\.pdf$//;
print "Adding $patId, file = $filename\n";
print $fh "$patId,$filename\n" or die "File print error: $!";
close $fh or warn "close failed! - $!";
}
return;
}
The line that prints to the screen, prints perfectly.
If I take the file open/close and the first print statement out of the if block, it prints that line into the file, but not the data inside the block.
I've tried every combo I can think of and it doesn't work. I've alternated between '>' and '>>' since it clearly needs the append since it's looping over filenames, but neither works inside the if block.
Even this code above doesn't throw the die errors! It just ignores those lines! I'm figuring there's something obvious I'm missing.
Quoting File::Find::find's documentation:
Additionally, for each directory found, it will chdir() into that directory
It means that when you open inside findAllFiles, you are potentially opening a file filenames.csv inside a subdirectory of your initial directory. You can run something like find . -name filenames.csv from your terminal, and you'll see plenty of filenames.csv. You can change this behavior by passing no_chdir option to find:
find( { wanted => \&findAllFiles, no_chdir => 1}, '.');
(and additionally changing > for >> in your open)
However, personally, I'd avoid repeatedly opening and closing filenames.csv when you could open it just once before calling find. If you don't want to have your filehandle globally defined, you can always pass it as an argument to findAllFiles:
{
open my $fh, '>', 'filenames.csv' or die "Failed to open 'filenames.csv': $!";
find(sub { findAllFiles($fh) }, '.')
}
sub findAllFiles {
my ($fh) = #_;
...
filenames.csv will be created in the directory where the pdf is found, since find() changes directories as it searches. If that's not what you want, use an absolute path to open it (or open it before calling find, which seems like a better idea).

Cannot decode! Invalid Base58 Character(s)!

I am trying to run
base58perl.pl
in my terminal using the following command:
perl base58perl.pl
but I get the following error:
Cannot decode! Invalid Base58 Character(s)!
Here's the code:
my $fileSrc = 'base58.txt';
open my $fhSrc, $fileSrc or die "Could not open $fileSrc: $!";
my $fileDest = 'hex.txt';
open( my $fhDest, '>>', $fileDest) or die "Could not open file $fileDest: $!";
while ( my $base58_encoded_address = <$fhSrc >) {
my $binary_address = decodebase58tohex($base58_encoded_address);
say $fhDest $binary_address;
}
close $fhSrc;
close $fhDest;
The content of base58.txt is a list of BTC address in base58 form.
I also have tried
chmod a+x base58perl.pl
perl base58perl.pl
base58.txt contents:
1E5PBfSaFawBy1RjBHkS6FDtCwXkYSsVTo
1DCgptTS2uY2occbVdW1qcVT72T75RXbyg
1CUNEBjYrCn2y1SdiUMohaKUi4wpP326Lb
I still get the same error.
That error message comes from the unbase58 function in the code you have linked.
die "Cannot Decode! Invalid Base58 Character(s)!\n" unless $bitcoin_address =~ /^[1-9A-HJ-NP-Za-km-z]*$/;
That line checks if the input contains only characters of the character group [1-9A-HJ-NP-Za-km-z]. Since your input does, it must dislike something else.
My guess is that it disliked the newline characters at the end of your lines. You need to chomp them off before passing the value to decodebase58tohex.
while( my $base58_encoded_address = <$fhSrc>) {
chomp $base58_encoded_address;
my $binary_address = decodebase58tohex($base58_encoded_address);
say $fhDest $binary_address;
}
You probably need to remove whitespace. You appear to be passing only chunks of the string to the decode function at a time, which could also be a problem. Read the whole file into a var, remove any whitespace, then decode.
my $base58_encoded_address = do { local $/; <$fhSrc> };
$base58_encoded_address =~ s/\s+//g;
my $binary_address = decodebase58tohex($base58_encoded_address);
say $fhDest $binary_address;
my $fileSrc = 'base58.txt';
open my $fhSrc, $fileSrc or die "Could not open $fileSrc: $!";
my $fileDest = 'hex.txt';
open( my $fhDest, '>>', $fileDest) or die "Could not open file $fileDest: $!";
my #tmp = <$fhSrc>;
chomp #tmp;
for my $line (#tmp) {
print "decoding '$line'\n";
my $binary_address = decodebase58tohex($line);
say $fhDest $binary_address;
}
close $fhSrc;
close $fhDest;
As someone else mentioned I think your dealing with whitespaces.
chomp will take care of that for you.
The next thing to do is print the string you are trying to decode in quotes which will confirm your only decoding what you want to.
The script is now working properly, the problem was the base58.txt the file was created using notepad. I created a new file using a different text editor.

Picking a specific line with a specific string

I am trying this in Perl to pick one complete line from whole document which contains "CURRENT_RUN_ID". I have been using below code to accomplish the above said task but I am unable to enter the while loop.
my $sSuccessString = "CURRENT_RUN_ID";
open(LOG, "$slogfile") or die("Can't open $slogfile\n");
my $sLines;
{
local $/ = undef;
$sLines=<LOG>;
}
my $spool = 0;
my #matchingLines;
while (<LOG>)
{
print OUTLOG "in while loop\n";
if (m/$sSuccessString/i) {
print OUTLOG "in if loop\n";
$spool = 1;
print map { "$_ \n" } #matchingLines;
#matchingLines = ();
}
if ($spool) {
push (#matchingLines, $_);
}
}
You are already done reading from the filehandle LOG after you have slurped it into $sLines. <LOG> in the head of the while will return undef because it has reached eof. You either have to use that variable $sLines in your while loop or get rid of it. You're not using it anyway.
If you only want to print the line that matches, all you need to do is this:
use strict;
use warnings;
open my $fh_in, '<', 'input_file' or die $!;
open my $fh_out '>', 'output_file' or die $!;
while (my $line = <$fh_in>) {
print $fh_out $line if $line =~ m/CURRENT_RUN_ID/;
}
close $fh_in;
close $fh_out;
When you execute this code:
$sLines=<LOG>;
it reads all of the data from LOG into $sLines and it leaves the file pointer for LOG at the end of the file. So when you next try to read from that file handle with:
while (<LOG>)
nothing is returned as there is no more data to read.
If you want to read the file twice, then you will need to use the seek() function to reset the file pointer before your second read.
seek LOG, 0, 0;
But, given that you never do anything with $sLines I suspect that you can probably just remove that whole section of the code.
The whole thing with $spool and #matchingLines seems strange too. What were you trying to achieve there?
I think your code can be simplified to just:
my $sSuccessString = "CURRENT_RUN_ID";
open(LOG, $slogfile) or die("Can't open $slogfile\n");
while (<LOG>) {
print OUTLOG if /$sSuccessString/i/;
}
Personally, I'd make it even simpler, by reading from STDIN and writing to STDOUT.
my $sSuccessString = 'CURRENT_RUN_ID';
while (<>) {
print if /$sSuccessString/i/;
}
And then using Unix I/O redirection to connect up the correct files.
$ ./this_filter.pl < your_input.log > your_output.log

Error in file upload using perl "read() on unopened filehandle"

I am facing read the file error while i am uploading a file using perl like this
fileparse_set_fstype('MSWin32');
my ($OriginalName,$OriginalPath) = fileparse( $CgiRef->{'filename'} );
my $LocalName = $_ . $OriginalName;
open(FILE, ">$config->{'BASE_PATH'}/files/$LocalName")
or die "Could not open file:$!";
my $Req = new CGI;
while (read($Req->param('filename'), my $Buffer, 1024))
{
print FILE $Buffer;
}
close(FILE)
And There is no problem in accesing $CgiRef->{'$filename'} or any refernce variables.
please let me know where is the actual problem while uploading.
now it shows the error
read() on unopened filehandle
You're trying to read from the wrong place. In CGI-land, use $cgi->upload('varname') to get a filehandle on the object you're trying to receive.
This modified version of your snippet should work:
fileparse_set_fstype('MSWin32');
my ($OriginalName,$OriginalPath) = fileparse( $CgiRef->{'filename'} );
my $LocalName = $_ . $OriginalName;
open(FILE, ">", "$config->{'BASE_PATH'}/files/$LocalName")
or die "Could not open file:$!";
my $Req = CGI->new();
# Get the filehandle for the upload content
my $Req_file = $Req->upload('filename');
# Save to FILE
while (<$Req_file>) {
print FILE;
}
close(FILE);
Please note, always use the 3 param version of open. It's cleaner, safer, and clearer. See Modern Perl for an explanation.
A full example of the whole process from HTML form to CGI processing can be found here.

Open filehandle or assign stdout

I'm working in a program where the user can pass a -o file option, and output should be then directed to that file. Otherwise, it should go to stdout.
To retrieve the option I'm using the module getopt long, and that's not the problem. The problem is that I want to create a file handle with that file or assign stdout to it if the option was not set.
if ($opt) {
open OUTPUT, ">", $file;
} else {
open OUTPUT, # ???
}
That's because this way, later in my code I can just:
print OUTPUT "...";
Without worrying if OUTPUT is stdout or a file the user specified. Is this possible? If I'm doing a bad design here, please let me know.
This would be a good example on how to use select.
use strict;
use warnings;
use autodie;
my $fh;
if ($opt) {
open $fh, '>', $file;
select $fh;
}
print "This goes to the file if $opt is defined, otherwise to STDOUT."
Look at the open documentation. The easiest is to reopen STDOUT itself and not use a filehandle in your code.
if ($opt) {
open(STDOUT, ">", $file);
}
...
print "this goes to $file or STDOUT\n";
(Add some error checking of course.)
A constant item such as OUTPUT cannot be assigned. Using a variable such as $output works better. For example:
my ($output, $display_filename);
if ($opt)
{
if ($opt eq '-')
{
$display_filename = 'stdout';
$output = *STDOUT;
}
else
{
$display_filename = $opt;
open($output, '>', $opt) or
die("Cannot open $opt for writing: $!\n");
}
}
That way the program can print to standard output and/or to an output file:
print $output "This might go to a file\n";
print "Data written to $display_filename\n" if ($verbose);