Parmenides has asked for the wisdom of the Perl Monks concerning the following question:
I am working on a perl script as part of a book that I am reading through for fun. The first part of the script (which is all that I have completed so far) asks the user to name a file. It then coppies that file into a different file. When it is finished, it will search the file for a particular string and then replace that string with a new string.
Anyways, when I run the program, before anything displays, I get a message in my terminal saying:
"Name "main::READFILE" used only once: possible typo at ./findandreplace.plx line 17"
Then the program creates the write file as exptected, but at the end of the program the file is blank. Also, my terminal gives me this message just before closing the program:
"/home/rootless/Documents/test2.txt
readline() on unopened filehandle at ./findandreplace.plx line 19."
I am definitely opening a valid file with text. It is a plain text doccument that I created using cat > test.txt. Here is my code:
#!/usr/bin/perl -w
use strict;
#This program asks for an input file, output file, a string, and a rep
+lacement string. It then searches the input file for the string and
+substitutes it with a phrase of the user's choice.
#Get fielnaem and strings
my ($infile, $outfile, $string, $rstring) ;
print "What file should I parse?\n" ;
chomp($infile = <STDIN>) ;
print "What expression should I look for?\n" ;
chomp($string = <STDIN>) ;
print "What should I replace that string with?\n" ;
chomp($rstring = <STDIN>) ;
print "What new file should I create with your replacement string?\n"
+;
chomp($outfile = <STDIN>) ;
#Open the file, perform the substitutions, and create the new user nam
+ed file.
open (READFILE, "$infile") || die "Can not open your file for parsing:
+ $!" ;
open (WRITEFILE, ">$outfile") || die "Can not open new replacement fil
+e: $!" ;
while (<$infile>) {
print WRITEFILE "$_" ;
}
Re: Newby question
by Athanasius (Archbishop) on Aug 05, 2012 at 07:30 UTC
|
| [reply] [Watch: Dir/Any] [d/l] |
Re: Newby question
by CountZero (Bishop) on Aug 05, 2012 at 06:59 UTC
|
This must be a very old book you are reading.Nowadays it is customary to use the more secure 3 argument variant of open with a lexical filehandle. Also, you do not have to double quote your variables, unless you want to interpolate them into a string. open my $READFILE, '<', $infile or die "Can not open $infile for parsi
+ng: $!" ;
and open my $WRITEFILE, '>', $outfile or die "Can not open new replacement
+ file: $outfile. $!";
Your loop will then be written as follows: while (<$READFILE>) {
# do something to $_
print $WRITEFILE $_ ;
}
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James My blog: Imperial Deltronics
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
I am reading a book called learning perl. It is from 1999 so yes it is old. Do you know of a newer book that includes exercizes in the chapters?
Also, big thanks to you all. I got this piece working :)
| [reply] [Watch: Dir/Any] |
|
If this is 'Learning Perl' by Randal Schwartz, et al., then the fifth edition was published last year by O'Reilly. I'd strongly recommend buying it, Perl has had a few changes in the past 13 years.
Update: Fixed typo
----
I Go Back to Sleep, Now.
OGB
| [reply] [Watch: Dir/Any] |
|
Re: Newby question
by aitap (Curate) on Aug 05, 2012 at 10:04 UTC
|
In addition to the comments above, it is usually helpful to use diagnostics; (see perldoc diagnostics) when you receive a strange warning. For example,
$ perl -w -e 'close FILEHANDLE; print <FILEHANDLE>'
readline() on closed filehandle FILEHANDLE at -e line 1.
$ perl -w -Mdiagnostics -e 'close FILEHANDLE; print <FILEHANDLE>'
readline() on closed filehandle FILEHANDLE at -e line 1 (#1)
(W closed) The filehandle you're reading from got itself closed so
+metime
before now. Check your control flow.
$ perl -w -Mdiagnostics -e 'my $s="text"; print <$s>'
readline() on unopened filehandle at -e line 1 (#1)
(W unopened) An I/O operation was attempted on a filehandle that w
+as
never initialized. You need to do an open(), a sysopen(), or a so
+cket()
call, or call a constructor from the FileHandle package.
$
(see perldoc perlrun if you want to know about -M and -e arguments)
EDIT: perldoc links
Sorry if my advice was wrong.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Newby question
by davido (Cardinal) on Aug 05, 2012 at 07:01 UTC
|
In line 17 you open a file. The filehandle is stored in a typeglob called READFILE, and the file's name is stored in the scalar variable $infile.
In line 19 you attempt to read from a filehandle held in $infile. But it's not intended to be used as a filehandle; it's just a string holding the name of a file that the user entered in line 8. You should change line 19 to: while(<READFILE>){.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Newby question
by Anonymous Monk on Aug 05, 2012 at 06:36 UTC
|
what book?
$infile is not a file handle, $infile is not READFILE
| [reply] [Watch: Dir/Any] |
Re: Newby question
by Marshall (Canon) on Aug 05, 2012 at 16:24 UTC
|
#!/usr/bin/perl -w
use strict;
#This program asks for an input file, output file, a string,
# and a replacement string. It then searches the input file
# for the string and substitutes it with a phrase of the
# user's choice.
#get user input...
#there are many problems with this code...
#Open the file, perform the substitutions, and create the
# new user named file.
open (READFILE, "$infile")
|| die "Can not open input file $infile: $!" ;
open (WRITEFILE, ">$outfile")
|| die "Can not create outfile $outfile: $!;
while (<$infile>) { ### PROBLEM ###
### Should use READFILE, the file handle ###
### instead of the string "$infile" ###
### while (<READFILE>) ###
print WRITEFILE "$_" ;
}
The $! variable can be useful, but it is often not.
This is basically the OS error code text. That does not normally
contain the file name that that was "under question".
If want to "die" or "warn", then I would echo the file name that
didn't work. | [reply] [Watch: Dir/Any] [d/l] |
|
That sounds useful. How do I do that?
| [reply] [Watch: Dir/Any] |
|
Below are some examples of "die" messages on my Windows machine for a non-existent file. I used "warn" instead of "die" so that all 4 examples would run.
In the first example, I just have the OS error code $!. Well if the code is opening many files, "which file?" is not known - although you can get the Perl source line that the error occurred on. I don't expect users to have to look into the code so that isn't ideal.
The second example, I put the filename that was trying to be opened into the "die" message. That is often way more useful than the OS error code alone. Usually not to hard to figure out why that file couldn't be opened.
In the third example, I put both the filename and error code. I most often include both pieces of information. Also note that I also put whether a read, write or append was attempted into the error message.
In the fourth example, I suppress the output of the Perl source line number by simply appending a "\n" to the "die" string. In a lot of situations, the user doesn't care about this Perl code line and it just clutters things up and can confuse folks.
#!/usr/bin/perl -w
use strict;
my $infile = 'bogus_name';
open IN, '<', $infile or warn "$!";
# No such file or directory at C:\TEMP\demoOpenMessage.pl line 6.
open IN, '<', $infile or
warn "cannot open $infile for reading";
#cannot open bogus_name for reading
# at C:\TEMP\demoOpenMessage.pl line 6.
open IN, '<', $infile or
warn "cannot open $infile for read-> $!";
#cannot open bogus_name for read-> No such file
# or directory at C:\TEMP\demoOpenMessage.pl line 12.
open IN, '<', $infile or
warn "cannot open $infile for read-> $!\n";
#cannot open bogus_name for read-> No such file or directory
| [reply] [Watch: Dir/Any] [d/l] |
|
|