Perl Readline on closed filehandle - file does not exist error - perl

I am working on a simple perl program for my first assignment in my programming class. I literally have been stuck on this first part for more than a day. I cannot get my program to simply open a text file that is in the same directory as the program.
#!/usr/bin/perl -w
use strict;
my($fileName, $line);
print "Please enter name of file to be opened: ", "\n";
$fileName = <STDIN>;
chop($fileName);
#Associates FILE filehandle with the file: "filename.txt"
open(FILE, $fileName) or die("Can't open '$fileName': $!");
while(my $line = <FILE>){
print $line;
}
I am using strawberry perl. To run the program I am dragging and dropping the program into the command line to get the address of the program. It then attempts to run it.
It initially gave me a readline on closed filehandle error, and then I included the or die("Can't open '$fileName': $!"); portion of the code.
Now it says that there is no such file at the directory, but I know that the test.txt file is there because I just created it.
Picture of the code results: http://imgur.com/R8s7FFE
File directory that shows locations of my files: http://imgur.com/nUfM4lA)

The prompt is showing C:\Users\jacjar\Documents as the current working directory
So this is where the program will look for test.txt
But it is not in that directory
text.txt is in L:\College\Junior Year\1st Semester\COSC 320 (Programming Languages)
Move your test.txt file to the C: path shown above and it will work

Do you realize you are trying to open C:\User\jacjar\Documents\test.txt?

Related

How to modify content of a file using single file handle

I'm trying to modify content of a file using Perl.
The following script works fine.
#!/usr/bin/perl
use strict;
use warnings;
open(FH,"test.txt") || die "not able to open test.txt $!";
open(FH2,">","test_new.txt")|| die "not able to opne test_new.txt $!";
while(my $line = <FH>)
{
$line =~ s/perl/python/i;
print FH2 $line;
}
close(FH);
close(FH2);
The content of test.txt:
im learning perl
im in File handlers chapter
The output in test_new.txt:
im learning python
im in File handlers chapter
If I try to use same file handle for modifying the content of file, then I'm not getting expected output. The following is the script that attempts to do this:
#!/usr/bin/perl
use strict;
use warnings;
open(FH,"+<","test.txt") || die "not able to open test.txt $!";
while(my $line = <FH>)
{
$line =~ s/perl/python/i;
print FH $line;
}
close(FH);
Incorrect output in test.txt:
im learning perl
im learning python
chapter
chapter
How do I modify the file contents using single file handle?
You can't delete from a file (except at the end).
You can't insert characters into a file (except at the end).
You can replace a character in a file.
You can append to a file.
You can shorten a file.
That's it.
You're imagining you can simply replace "Perl" with "Python" in the file. Those aren't of the same length, so it would require inserting characters into the file, and you can't do that.
You can effectively insert characters into a file by loading the rest of the file into memory and writing it back out two characters further. But doing this gets tricky for very large files. It's also very slow since you end up copying a (possibly very large) portion of the file every time you want to insert characters.
The other problem with in-place modifications is that you can't recover from an error. If something happens, you'll be left with an incomplete or corrupted file.
If the file is small and you're ok with losing the data if something goes wrong, the simplest approach is to load the entire file into memory.
open(my $fh, '<+', $qfn)
or die("Can't open \"$qfn\": $!\n");
my $file = do { local $/; <$fh> };
$file =~ s/Perl/Python/g;
seek($fh, 0, SEEK_SET)
or die $!;
print($fh $file)
or die $!;
truncate($fh)
or die $!;
A safer approach is to write the data to a new file, then rename the file when you're done.
my $new_qfn = $qfn . ".tmp";
open(my $fh_in, '<', $qfn)
or die("Can't open \"$qfn\": $!\n");
open(my $fh_out, '<', $new_qfn)
or die("Can't create \"$new_qfn\": $!\n");
while (<$fh_in>) {
s/Perl/Python/g;
print($fh_out $_);
}
close($fh_in);
close($fh_out);
rename($qfn_new, $qfn)
or die $!;
The downside of this approach is it might change the file's permissions, and hardlinks will point to the old content instead of the new file. You also need permissions to create a file.
As #Сухой27 answered
it's typical situation that perl onliner pleasingly used.
perl -i -pe 's/perl/python/i'
perl takes below options
-p : make line by line loop(every line assign into $_ and print after evaluated $_)
-e : evaluate code block in above loop ( regex take $_ as default operand )
-i : in plcae file edit (if you pass arguments for -i, perl preserve original files with that extention)
if you run below script
perl -i.bak -pe 's/perl/python/i' test.txt
you will get modified test.txt
im learning python
im in File handlers chapter
and get original text files named in test.txt.bak
im learning perl
im in File handlers chapter

Issue while opening the file in Perl

I am trying to open a file using perl command. When I am passing a variable in between the file path, perl is not able to open the file: (here $line)
open(FL, "<C:/Users/admin/Documents/Projects/$line/project.txt") or die "Could not open file $!";
and If I try to open the file by passing the full path instead of variable ($line) in the path, Perl is able to open the file successfully:
open(FL, "<C:/Users/admin/Documents/Projects/projectName/project.txt") or die "Could not open file $!";
Could somebody please guide me how to achieve this. I have a list of projects and I cannnot pass name of every project manually but I need to achieve this by passing projectNames as the variables $line.
NOTE: All the $line variables are my projectNames.
Are you reading your project names from another file? If so, did you remember to remove \n at the end (using chomp $line or similar)?
Suppose your $line having some special character it won't allow, so we shopuld escape the character, use quotemeta
$line = qutoemeta($line);
open my $fh, "<" ,$line or die "Error opening $!";
You will fix the error by $!. Already you have added it in your code.
Please follow what it is saying.

How do I drop a file onto a perl script to parse it and write the output file to the same directory

I have a working perl script that opens a imput file, parse it and then open a output file and write the parsed output to it. Now I want to be able to drop a file to be script. The file should be read and the written file should have the same name with a different extension and be stored in the same directory(!) where the file was dropped from. The script itself is converted to a exe using PAR:Packer. I'm using Windows 7 and the latest version Strawbery Perl (5.16.2)
The way I check for the file name is :
unless ($#ARGV == -1) {
$filename = $ARGV[0];
}
This is how I open the input file :
open (my $mel, "<", $filename) or die "\nFile does not exist.\n";
And this is how I open the output file :
open (my $out, ">", 'majorEventLog.Prs') or die "Can't open output file: $!";
The issue I face is that the input file is not recognised at all. Second, what do I need to do to have the output file to be created in the same directory ? When I created a cmd file the input file worked but it stored the output file in my home directory. But I do not like to use the CMD, and I also would like to have the output file in the same directory than the input file. How do I need to change my code?
Use this to get input file name:
my $filename = shift;
die ("Please provide input file\n") unless defined $filename;
die ("$filename does not exist\n") unless -f $filename;
Use this to generate output filename in the same directory:
use File::Basename;
use File::Spec;
my ($name, $directory, $suffix) = fileparse($filename);
my $outfile = File::Spec->catfile($directory, "output.txt");

Why is piping my script's output into the shell's dir command not working as I expected?

I am piping the directory command output to file handle, followed by the print to the file handle. I wish to append some text to the dir/ls output.
open (FH, "| dir") or die "$OS_ERROR";
print FH ("sometext") or die "$OS_ERROR";
while (<FH>){
print;
}
When I execute the Perl script, I see the directory contents, but I do not see the text printed using the print statement, in this case I do not see sometext. What am I missing?
To explain in more detail - I want pipe dir contents to FH, and following that I want to append some text to the same filehandle FH . I have referred link http://perldoc.perl.org/perlopentut.html#Pipe-Opens
You are not redirecting anything: You are piping your script's output to either the cmd.exe builtin dir or an alias to ls depending on your OS (which means, you might run into trouble if you run this script with Cygwin's ls in your path on Windows).
Writing to dir does not seem useful. If you wanted to filter dirs output, i.e. take the output from running dir and manipulate it before printing, you should pipe it into your script and you should print the processed output.
#!/usr/bin/env perl
use strict; use warnings;
my $pid = open my $dir_out, '-|', 'cmd.exe /c dir';
die "Cannot open pipe: $!\n" unless $pid;
my $output_file = 'output.txt';
open my $my_out, '>', $output_file
or die "Cannot open '$output_file': $!";
while (my $line = <$dir_out>) {
$line =~ s/bytes free/peons liberated/;
print $my_out $line;
}
close $my_out
or die "Cannot close '$output_file': $!";
close $dir_out
or die "Cannot close pipe: $!\n";
Of course, I am assuming there are other things going on in your program and this is only a small part of it. Otherwise, you don't need to write this much code for a simple filter.
You cannot write to FH with print and then expect to read from FH in the next statement. File handles are not FIFOs (by default).
The open gives you a writable file handle, the read end of which is connected to the stdin of dir. Reading from a write file handle just gives you nothing.
What do you actually want to achieve? Send some text to the dir program, or read output of the dir program?
Since in the comment you said you want to read the output of the dir command, you have the open command wrong; use "dir |" instead of "| dir" and read the Perl Open Tutorial.
Maybe this does what you want to do:
open (FH, "dir|") or die "$OS_ERROR";
while (<FH>){
print;
}
print "sometext\n";

How to read multiple files from a directory, extract specific strings and ouput to an html file?

Greetings,
I have the following code and am stuck on how I would proceed to modify it so it will ask for the directory, read all files in the directory, then extract specific strings and ouput to an html file? Thanks in advance.
#!/usr/local/bin/perl
use warnings;
use strict;
use Cwd;
print "Enter filename: "; # Should be Enter directory
my $perlfile =STDIN;
open INPUT_FILE, $perlfile || die "Could not open file: $!";
open OUTPUT, '>out.html' || die "Could not open file: $!";
# Evaluates the file and imports it into an array.
my #comment_array = ;
close(INPUT_FILE);
chomp #comment_array;
#comment_array = grep /^\s*#/g, #comment_array;
my $comment;
foreach $comment (#comment_array) {
$comment =~ /####/; #Pattern match to grab only #s
# Prints comments to screen
Print results in html format
# Writes comments to output.html
Writes results to html file
}
close (OUTPUT);
Take it one step at a time. You have a lot planned, but so far you haven't even changed your prompt string to ask for a directory.
To read the entered directory name, your:
my $perlfile =STDIN;
gives an error (under use strict;). Start by looking that error up (use diagnostics; automates this) and trying to figure out what you should be doing instead.
Once you can prompt for a directory name and print it out, then add code to open the directory and read the directory. Directories can be opened and read with opendir and readdir. Make sure you can read the directory and print out the filenames before going on to the next step.
a good starting point to learn about specific functions (from the cmd line)
perldoc -f opendir
However, your particular problem is answered as follows, you can also use command line programs and pipe them into a string to simplify file handling ('cat') and pattern matching ('grep').
#!/usr/bin/perl -w
use strict;
my $dir = "/tmp";
my $dh;
my #patterns;
my $file;
opendir($dh,$dir);
while ($file = readdir($dh)){
if (-f "$dir/$file"){
my $string = `cat $dir/$file | grep pattern123`;
push #patterns, $string;
}
}
closedir($dh);
my $html = join("<br>",#patterns);
open F, ">out.html";
print F $html;
close F;