How can get a filehandle for a Perl program's output? - perl

I have an encrypted file X1, I have a Perl program P1 that decrypts the X1. I am parsing the decrypted file using a Perl program p2.
X1--P1(decrypter) --> X2(plain text file) --p2(parser) --> parse output
My parser is based on XML::Parser. It can work with a filehandle to the decrypted file. Now I am getting the X2 and storing it in the file system and reading it in the P2 and parsing it. Is there way I can directly get the filehandle over the P1's output and use that filehandle in the P2 to parse it directly with out requiring a temporary file?

Say you're using very weak encryption:
#! /usr/bin/perl
print <<EOXML;
<doc>
<elem attr="Hello, world!" />
</doc>
EOXML
Using open $fh, "-|", ... will create a pipe connected to the standard output of a child process:
#! /usr/bin/perl
use warnings;
use strict;
open my $decrypted, "-|", "./decrypt"
or die "$0: open: $!";
while (<$decrypted>) {
print "got: $_";
}
Output:
got: <doc>
got: <elem attr="Hello, world!" />
got: </doc>

I'm not sure I entirely understand what you're getting at, but it sounds like you just want to use pipes. You can do that at the shell by redirecting one program's STDOUT to another's STDIN
$ foo | bar
Or you can do it within Perl by opening a pipe directly to another program.
See also IPC::Open3 if you need control over STDERR.

Why don't you just make your programs read from STDIN and write to STDOUT and pipe the commands together on the command line?

Related

How to read a .conf file in Perl

I just created a text test.conf file with some information. How can I read it on Perl?
I am new to Perl and I am not sue would will I need to do.
I tried the following:
C:\Perl\Perl_Project>perl
#!/usr/local/bin/perl
open (MYFILE, 'test.conf');
while (<MYFILE>)
{ chomp; print "$_\n"; }
close (MYFILE);
I tried installing Perl on my laptop that has Windows 7 OS, and using command line.
Instead of using command line, write your program in a file (you can use any editor to write your program, I would suggest use Notepad++) and save as myprogram.pl in the same directory where you have your .conf file.
use warnings;
use strict;
open my $fh, "<", "test.conf" or die $!;
while (<$fh>)
{
chomp;
print "$_\n";
}
close $fh;
Now open a command prompt and go to the same path where you have your both file myprogram.pl and test.conf file and execute your program by typing this:
perl myprogram.pl
You can give full path of your input file inside program and can run your program from any path from command prompt by giving full path of your program:
perl path\to\myprogram.pl
Side note: Always use use warnings; and use strict; at the top of your program and to open file always use lexical filehandle with three arguments with error handling.
This is an extended comment more than an answer, as I believe #serenesat has given you everything you need to execute your program.
When you do "command line" Perl, it's typically stuff that is relatively brief or trivial, such as:
perl -e "print 2 ** 16"
Anything that goes beyond a few lines, and you're probably better off putting that in a file and having Perl run the file. You certainly can put larger programs on the command line, but when it comes to going back in and editing lines, it becomes more of a hassle than a shortcut.
Also, for what it's worth the -n and -p parameters allow you to process the contents of a stream, meaning you could do something like this:
perl -ne "print if /oracle/i" test.conf

Handling and generating files in Perl code

I have perl code (called aggregator.pl) that reads some data from a file called 'testdata.csv' through the command
open (F,'testdata.csv');
my #lines=<F>;
close(F);
opens a new file handle for the output
open (F1,'>>testdata_aggregates.csv');
and appends to this output file 'testdata_aggregates.csv' the results of some calculations.
To launch my perl code I simply type in my command prompt:
$ perl aggregator.pl
Now, I have different data files, called e.g 20100909.csv or 20100910.csv and I would like to change my perl code so that when I launch my code from the command prompt I tell perl the name of the input file he should use (say, '20100909.csv') and that he should name the output file accordingly (say '20100909_aggregates.csv', basically, adding _aggregates to the input filename).
Any advice on how to change my code and how would I have to launch the new code adding the name of the data_input file he should use?
Just accept parameters via #ARGV.
Your script should open with:
use strict;
use warnings;
use autodie;
die "Usage: $0 Input_File Output_File\n" if #ARGV != 2;
my ($infile, $outfile) = #ARGV;
And later in your file
open (F, '<', $infile);
# ...
open (F1,'>>', $outfile);
One would usually rewrite such an application that it reads from STDIN and simply writes to STDOUT. When the program is then invoked on the command line, redirection operators can be used to specify the files:
$ perl aggregator.pl <testdata.csv > testdata_aggregates.csv
$ perl aggregator.pl <20100909.csv > 20100909_aggregates.csv
...
What changes inside the script? We don't open a file F, instead: my #lines = <>. We don't print to F1, instead we print to STDOUT, which is selected implicitly: print F1 "foo\n" becomes print "foo\n".

From inside a perl script can you know the name of the file you are redirecting output to?

So I have:
test.pl > test.log
is there a way to know inside test.pl that I am outputing to 'test.log'? At the end of my script I want to do some manipulation of test.log without hardcoding the name.
Maybe. The following works on Linux, but will not be very portable to other systems...
#!/usr/bin/env perl
use strict;
use warnings;
my $out = readlink("/proc/$$/fd/1");
print STDERR "I am being output to $out\n";
Naturally, this is probably a bad idea. Better to explicitly open the file and write to it in Perl, rather than having the shell set up redirections.
You can redirect standard output from perl, with minimal changes to your script,
test.pl test.log
my ($file) = #ARGV;
if (#ARGV) {
open STDOUT, ">", $file or die $!;
}
print "output is redirected to $file\n";
# use $file at the end

How read/write into a named pipe in perl?

I have a script which have their input/output plugged to named pipes. I try to write something to the first named pipe and to read the result from the second named pipe but nothing happen.
I used open then open2 then sysopen whithout success :
sysopen(FH, "/home/Moses/enfr_kiid5/pipe_CGI_Uniform", O_RDWR);
sysopen(FH2, "/home/Moses/enfr_kiid5/pipe_Detoken_CGI", O_RDWR);
print FH "test 4242 test 4242" or die "error print";
doesn't made error but didn't work : i can't see trace of the print, the test sentence is not write into the first named pipe and try to read from the second block the process.
Works here.
$ mkfifo pipe
$ cat pipe &
$ perl -e 'open my $f, ">", "pipe"; print $f "test\n"'
test
$ rm pipe
You don't really need fancy sysopen stuff, named pipes are really supposed to behave like regular files, albeit half-duplex. Which happens to be a difference between your code and mine, worth investigating if you really need this opening pattern.
You may need to unbuffer your output after opening the pipe:
sysopen(...);
sysopen(...);
$old=select FH;
$|=1;
select $old;
print FH...
And, as friedo says, add a carriage return ("\n") to the end of your print statement!

How can I append the file foo2.txt to foo1.txt?

Is there any method to execute foo2.pl from foo1.pl in Perl, and append the foo2.txt to the foo1.txt then create foo3.txt? thanks.
i.e.
foo1.pl
print "Hello"; # output to foo1.txt;
foo2.pl
print "World"; # output to foo2.txt;
How to create foo3.txt file based on foo1.pl.
foo3.txt
Hello
World
Something like append foo2.txt to foo1.txt.
As i know, I can open foo1.txt and foo2.txt, then include the lines in foo3.pl.
print FOO3_TXT (<FOO1_TXT>);
print FOO3_TXT (<FOO2_TXT>);
Is there any good method?
Update my test (ActivePerl 5.10.1)
My foo.pl
#!C:\Perl\bin\perl.exe
use strict;
use warnings;
print "world\n";
my hw.pl (foo.pl and hw.pl at the same directory)
#!C:\Perl\bin\perl.exe
use strict;
use warnings;
print 'hello ';
print `./foo.pl`;
Output
**D:\learning\perl>hw.pl
hello '.' is not recognized as an internal or external command,
operable program or batch file.**
If hw.pl updated {}:
#!C:\Perl\bin\perl.exe
use strict;
use warnings;
print q{hello }, qx{./foo.pl};
Now Output. (a little different for the loacation of hello)
D:\learning\perl>hw.pl
'.' is not recognized as an internal or external command,
operable program or batch file.
hello
[Update].
Fixed. see answer,
run this as a script
perl foo1.pl > foo3.txt;
perl foo2.pl >> foo3.txt;
contents of foo1.pl
!#/bin/perl
print "Hello";
contents of foo2.pl
!#/bin/perl
print "World";
or
simply use the cat command if you are running linux to append foo2.txt to foo1.txt.
Just in case you are being literal about execute foo2.pl from foo1.pl in Perl then this is what you can do:
print 'hello ';
print qx(perl foo2.pl);
qx is another way to run system commands like backticks. Thus perl foo2.pl is run with the output being sent back to your calling perl script.
So here the same using backticks. Also it uses a direct call to script (which is better):
print 'hello ';
print `./foo2.pl`;
And if you are expecting lots of output from the script then its best not to load it all into memory like above two examples. Instead use open like so:
print 'hello ';
open my $foo2, '-|', './foo2.pl';
print <$foo2>;
close $foo2;
And you can wrap this up into one print statement for "hello world" example:
print 'hello ', do {
open my $foo2, '-|', './foo2.pl';
<$foo2>;
};
/I3az/
Using a shell script (for example, a .bat file on Windows) to run various Perl scripts and combine their output is one way to solve the problem. However, I usually find that Perl itself provides a more powerful and flexible environment than shell scripts. To use Perl in this way, one place to start is by learning about the system and exec commands.
For example:
# In hello.pl
print "Hello\n";
# In world.pl
print "World\n";
# In hello_world.pl.
use strict;
use warnings;
system 'perl hello.pl > hello_world.txt';
system 'perl world.pl >> hello_world.txt';
You can use the following code also
file1.pl
use strict;
use warnings;
open (FH,">file") or die "$! can't open";
print FH "WELCOME\n";
file2.pl
use strict;
use warnings;
open (FH,">>file") or die "$! can't open";
print FH "WELCOME2\n";
The file content is
WELCOME
WELCOME2
If you know beforhand that the script you want to execute from inside the other script is also Perl, you should use do EXPR (https://perldoc.perl.org/functions/do.html).
This executes the contents of the file EXPR in the context of the running perl process and saves you from starting new cmd.exe and perl.exe instances.
hello.pl:
print "Hello";
do "world.pl";
wordl.pl:
print "World";