Why am I getting error print() on closed filehandle in Perl - perl

I am trying to write output to one C file but I'm getting an error about print() on closed filehandle.
my $fileoutput="output.c";
open OUTFILE, "> $fileoutput" or die $!;
for my $i (keys%hash) {
# grep for c file output and compare
# with xml key print both key and values
if (grep $_ eq $i,#c_result_array) {
if (defined $hash{$i}) {
my #values = $hash{$i};
print OUTFILE $i . "=> #values";
print OUTFILE "\n";
}
close OUTFILE;
}
}

You close the output file inside the for loop. By the second iteration, the file handle has been closed. You have to close the file once the loop has run to completion.
Also, bareword file handles have package scope which comes with all the disadvantages of global variables. Use lexical file handles.
Also, especially if the name of the file you are opening is coming from the outside, use the three argument form of open, and always include the name of the file in error messages.
Finally, presumably, $hash{$i} contains an array reference, so you have to dereference it if you are going to interpolate its contents into a string.
my $fileoutput = "output.c";
open my $OUTFILE, '>', $fileoutput
or die "Failed to open '$fileoutput': $!";
for my $i (keys %hash) {
#grep for c file output and compare with xml key print both key and values #
if (grep $_ eq $i, #c_result_array) {
if(defined $hash{$i}) {
my #values = #{ $hash{$i} };
print $OUTFILE "$i => #values\n";
}
}
}
close $OUTFILE
or die "Failed to close '$fileoutput': $!";

Related

perl: print output of subroutine to file

How to write the output of a subroutine to file?
my $logfile="C:/Test/report_p3.txt";
open(my $tt, ">",$logfile) or die "Can not open file";
foreach (#files)
{
if (($_ ne ".") && ($_ ne ".."))
{
&getinfo($logdir."/".$_);
print $tt &getinfo; #Here, I wanna pass the output to the handler
}
}
close $tt;
on standard output, &getinfo prints correctly the output.
Open a filehandle that outputs into a variable, and select it.
After that all output going into STDOUT will be caught in the variable.
Here is an example:
sub output {
print "test\n";
}
my $out;
open VAROUT, '>', \$out;
select VAROUT;
output();
select STDOUT;
printf "output: %s\n", $out;
Is it really necesssary, that the subroutine, whose output you want to pass actually prints something?
Usually you should simply make your sub return a string and have the caller decide where to output it.
my $logfile="C:/Test/report_p3.txt";
open(my $tt, ">",$logfile) or die "Can not open file";
sub get_log {
return "some text to log";
}
sub log_write {
my $log_fh = shift;
print $log_fh get_log() . "\n";
}
log_write($tt); # prints to file handle from $tt
log_write(STDOUT); # prints to STDOUT

How to use text output from one perl script as input to another perl script? I seem to be able run this as two separate scripts but not as one

I've got a script that reformats an input file and creates an output file. When I try to read that output file for the second part of the script, it doesn't work. However if I split the script into two parts it works fine and gives me the output that I need. I'm not a programmer and surprised I've got this far - I've been banging my head for days trying to resolve this.
My command for running it is this (BTW the temp.txt was just a brute force workaround for getting rid of the final comma to get my final output file - couldn't find another solution):
c:\perl\bin\perl merge.pl F146.sel temp.txt F146H.txt
Input looks like this (from another software package) ("F146.sel"):
/ Selected holes from the .\Mag_F146_Trimmed.gdb database.
"L12260"
"L12270"
"L12280"
"L12290"
Output looks like this (mods to the text: quotes removed, insert comma, concatenate into one line, remove the last comma) "F146H.txt":
L12260,L12270,L12280,L12290
Then I want to use this as input in the next part of the script, which basically inserts this output into a line of code that I can use in another software package (my "merge.gs" file). This is the output that I get if I split my script into two parts, but it just gives me a blank if I do it as one (see below).
CURRENT Database,"RAD_F146.gdb"
SETINI MERGLINE.OUT="DALL"
SETINI MERGLINE.LINES="L12260,L12270,L12280,L12290"
GX mergline.gx
What follows is my "merge.pl". What have I done wrong?
(actually, the question could be - what haven't I done wrong, as this is probably the most retarded code you've seen in a while. In fact, I bet some of you could get this entire operation done in 10-15 lines of code, instead of my butchered 90. Thanks in advance.)
# this reformats the SEL file to remove the first line and replace the " with nothing
$file = shift ;
$temp = shift ;
$linesH = shift ;
#open (Profiles, ">.\\scripts\\P2.gs")||die "couldn't open output .gs file";
open my $in, '<', $file or die "Can't read old file: Inappropriate I/O control operation";
open my $out, '>', $temp or die "Can't write new file: Inappropriate I/O control operation";
my $firstLine = 1;
while( <$in> )
{
if($firstLine)
{
$firstLine = 0;
}
else{
s/"L/L/g; # replace "L with L
s/"/,/g; # replace " with,
s|\s+||; # concatenates it all into one line
print $out $_;
}
}
close $out;
open (part1, "${temp}")||die "Couldn't open selection file";
open (part2, ">${linesH}")||die "Couldn't open selection file";
printitChomp();
sub printitChomp
{
print part2 <<ENDGS;
ENDGS
}
while ($temp = <part1> )
{
print $temp;
printit();
}
sub printit
{$string = substr (${temp}, 0,-1);
print part2 <<ENDGS;
$string
ENDGS
}
####Theoretically this creates the merge script from the output
####file from the previous loop. However it only seems to work
####if I split this into 2 perl scripts.
open (MergeScript, ">MergeScript.gs")||die "couldn't open output .gs file";
printitMerge();
open (SEL, "${linesH}")||die "Couldn't open selection file";
sub printitMerge
#open .sel file
{
print MergeScript <<ENDGS;
ENDGS
}
#iterate over required files
while ( $line = <SEL> ){
chomp $line;
print STDOUT $line;
printitLines();
}
sub printitLines
{
print MergeScript <<ENDGS;
CURRENT Database,"RAD_F146.gdb"
SETINI MERGLINE.OUT="DALL"
SETINI MERGLINE.LINES="${line}"
GX mergline.gx
ENDGS
}
so I think all you were really missing was close(part2); to allow it to be reopened as SEL..
#!/usr/bin/env perl
use strict;
use warnings;
# this reformats the SEL file to remove the first line and replace the " with nothing
my $file = shift;
my $temp = shift;
my $linesH = shift;
open my $in, '<', $file or die "Can't read old file: Inappropriate I/O control operation";
open my $out, '>', $temp or die "Can't write new file: Inappropriate I/O control operation";
my $firstLine = 1;
while (my $line = <$in>){
print "LINE: $line\n";
if ($firstLine){
$firstLine = 0;
} else {
$line =~ s/"L/L/g; # replace "L with L
$line =~ s/"/,/g; # replace " with,
$line =~ s/\s+//g; # concatenates it all into one line
print $out $line;
}
}
close $out;
open (part1, $temp) || die "Couldn't open selection file";
open (part2, ">", $linesH) || die "Couldn't open selection file";
while (my $temp_line = <part1>){
print "TEMPLINE: $temp_line\n";
my $string = substr($temp_line, 0, -1);
print part2 <<ENDGS;
$string
ENDGS
}
close(part2);
#### this creates the merge script from the output
#### file from the previous loop.
open (MergeScript, ">MergeScript.gs")||die "couldn't open output .gs file";
open (SEL, $linesH) || die "Couldn't open selection file";
#iterate over required files
while ( my $sel_line = <SEL> ){
chomp $sel_line;
print STDOUT $sel_line;
print MergeScript <<"ENDGS";
CURRENT Database,"RAD_F146.gdb"
SETINI MERGLINE.OUT="DALL"
SETINI MERGLINE.LINES="$sel_line"
GX mergline.gx
ENDGS
}
and one alternative way of doing it..
#!/usr/bin/env perl
use strict;
use warnings;
my $file = shift;
open my $in, '<', $file or die "Can't read old file: Inappropriate I/O control operation";
my #lines = <$in>; # read in all the lines
shift #lines; # discard the first line
my $line = join(',', #lines); # join the lines with commas
$line =~ s/[\r\n"]+//g; # remove the quotes and newlines
# print the line into the mergescript
open (MergeScript, ">MergeScript.gs")||die "couldn't open output .gs file";
print MergeScript <<"ENDGS";
CURRENT Database,"RAD_F146.gdb"
SETINI MERGLINE.OUT="DALL"
SETINI MERGLINE.LINES="$line"
GX mergline.gx
ENDGS

Avoid empty file creation

I want to split the large file in to small files by splitting at the specific line with the help of regex. Any help?
My code doing the job but it also creating a empty file.
#!/usr/local/lib/perl/5.14.2
open( INFILE, 'test.txt' );
#lines = <INFILE>;
$file = "outfile";
for ( $j = 0; $j <= $#lines; $j++ ) {
open( OUTFILE, ">", $file . $j );
$file_name = $file . $j;
#print "file is $file_name\n";
$i = 0;
while (#lines) {
$_ = shift #lines;
chomp;
$i++;
if ( $_ =~ /^###\s*(.*)\s*###/ && $i > 1 ) {
unshift #lines, "$_\n";
print "$filename\n";
last;
}
print OUTFILE "$_\n";
}
close(OUTFILE);
}
close(INFILE);
My input file contains :
-------------
### abcd hdkjfkdj ####
body 1 dsjklsjdfskl
### zyz fhid ###
abcdksdsd djnfkldsfmnsldk ;lkjfkl
---------------------------
it is creating 3 outfiles called outfile0,outfile1,outfile2. but outfile0 is empty I want to avoid this.
The way to fix it is to open the file only in response to the line being found. Your program will open a new file regardless and that's why it has an empty output file
Here is a rewrite that works. I've also removed the temporary #lines array
#!/usr/bin/perl
#
use warnings;
use strict;
open(my $file,"<", "test.txt") || die $!;
my $counter=1;
my $out;
while(<$file>) {
if (/###\s*(.*)\s*###/) {
open($out, ">", "outfile$counter") || warn "outfile$counter $!";
$counter++;
}
print $out $_ if $out;
}
If you want to use the material between the ### blocks as file titles, you can set the file name when you're doing the pattern match on the lines with ### blocks.
#!/usr/bin/perl
use strict;
use warnings;
open my $fh, '<', 'my_file.txt' or die "Could not open file: $!";
# initialise a variable that will hold the output file handle
my $out;
while (<$fh>) {
# capture the title between the # signs
if (/##+ (.*?) ##+/) {
open $out, '>', $1.".txt" or die "Could not create file $1.txt: $!";
}
elsif ($out) {
print $out $_;
}
else {
# if $out is not set, we haven't yet encountered a title block
warn "Error: line found with no title block: $_";
}
}
Sample input:
Text files containing their own name
### questions-1 ####
Why are a motorcycle's front brakes more effective than back?
Is it possible to make a gradient follow a path in Illustrator?
Text files containing their own name
### questions-2 ###
Why does Yoda mourn the Jedi after order 66 is executed?
what are the standard gui elements called?
Flybe just cancelled my return flight. Will they refund that part of the trip?
### questions-3 ###
Merge two arrays of ElementModels?
Is this set open or closed?
Output: three files, questions-1.txt, questions-2.txt, questions-3.txt, containing the appropriate lines. e.g. questions-1.txt:
Why are a motorcycle's front brakes more effective than back?
Is it possible to make a gradient follow a path in Illustrator?
Text files containing their own name
You haven't stated whether you want the ### lines in the output or not, so I've left them off.
Depending on what OS you're on and what your potential file names contain, you may want to filter them and replace special characters with an underscore (or just remove the special characters).

How to read from a file and direct output to a file if a file name is given in the command line, and printing to console if no argument given

I made a file, "rootfile", that contains paths to certain files and the perl program mymd5.perl gets the md5sum for each file and prints it in a certain order. How do I redirect the output to a file if a name is given in the command line? For instance if I do
perl mymd5.perl md5file
then it will feed output to md5file. And if I just do
perl mydm5.perl
it will just print to the console.
This is my rootfile:
/usr/local/courses/cs3423/assign8/cmdscan.c
/usr/local/courses/cs3423/assign8/driver.c
/usr/local/courses/cs3423/assign1/xpostitplus-2.3-3.diff.gz
This is my program right now:
open($in, "rootfile") or die "Can't open rootfile: $!";
$flag = 0;
if ($ARGV[0]){
open($out,$ARGV[0]) or die "Can't open $ARGV[0]: $!";
$flag = 1;
}
if ($flag == 1) {
select $out;
}
while ($line = <$in>) {
$md5line = `md5sum $line`;
#md5arr = split(" ",$md5line);
if ($flag == 0) {
printf("%s\t%s\n",$md5arr[1],$md5arr[0]);
}
}
close($out);
If you don't give a FILEHANDLE to print or printf, the output will go to STDOUT (the console).
There are several way you can redirect the output of your print statements.
select $out; #everything you print after this line will go the file specified by the filehandle $out.
... #your print statements come here.
close $out; #close connection when done to avoid counfusing the rest of the program.
#or you can use the filehandle right after the print statement as in:
print $out "Hello World!\n";
You can print a filename influenced by the value in #ARGV as follows:
This will take the name of the file in $ARGV[0] and use it to name a new file, edit.$ARGV[0]
#!/usr/bin/perl
use warnings;
use strict;
my $file = $ARGV[0];
open my $input, '<', $file or die $!;
my $editedfile = "edit.$file";
open my $name_change, '>', $editedfile or die $!;
if ($input eq "md5file"){
while ($in){
# Do something...
print $name_change "$_\n";
}
}
Perhaps the following will be helpful:
use strict;
use warnings;
while (<>) {
my $md5line = `md5sum $_`;
my #md5arr = split( " ", $md5line );
printf( "%s\t%s\n", $md5arr[1], $md5arr[0] );
}
Usage: perl mydm5.pl rootfile [>md5file]
The last, optional parameter will direct output to the file md5file; if absent, the results are printed to the console.

Reading and printing file contents using Perl

Can any body help me in reading all the files of particular format from the directory line by line and it should print on screen.
And my request is to include command lines in the program itself.
Then when ever simple I ran the program , it should display all the content of files.
Below is the program I wrote can any body help me please....
#!/usr/local/bin/perl
$filepath="/home/hclabv";
opendir(DIR,"$filepath");
#files=grep{/\.out$/} readdir(DIR);
closedir(DIR);
$c = 0;
for ($c=0 ;
while ($c <= #files)
{
$cmd = "Perlsc11 $files[$c]";
system($cmd);
if($#ARGV != 0) {
print STDERR "You must specify exactly one argument.\n";
exit 4;
}
else
{
print ("$files[$c]\n");
# Open the file.
open(INFILE, $ARGV[0]) or die "Cannot open $ARGV[0]: $!.\n";
while(my $l = <INFILE>) {
print $l;
}
close INFILE;
}
$c++;
}
You can use the glob feature in perl to get a list of filenames with the ".out" extension in the specified directory. You can then open these files one by one using a loop and print their contents to the screen. Here's the code,
# get all file-names with ".out" extension into array
my #outFiles = glob "/home/hclabv/*.out";
# loop through list of file names in array
foreach my $outFileName ( #outFiles )
{
# open the file for processing
open $outFile, '<', $outFileName or die "Unable to open file for reading : $!";
# iterate through each line in the file
while ( $line = <$outFile> )
{
# print the individual line
print "$line\n";
}
# close the file
close $outFile;
}
Please clarify what you mean by "including command lines", so we can help further.