Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Newby question

by Parmenides (Novice)
on Aug 05, 2012 at 06:33 UTC ( [id://985488]=perlquestion: print w/replies, xml ) Need Help??

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 "$_" ; }

Replies are listed 'Best First'.
Re: Newby question
by Athanasius (Archbishop) on Aug 05, 2012 at 07:30 UTC

    Hello Parmenides,

    Since this is a learning exercise, here are a couple of points to add to the excellent advice given by CountZero above:

    • Prefer the use warnings; pragma to the -w command line flag. The latter applies globally, so it may give warnings for modules you use in your code but over which you have no control. The former is lexically scoped, and can be turned on and off as needed. See warnings.

    • Despite the superficial similarities, Perl is not C, so you don’t need to declare your variables at the start of a block. It is better practice to declare lexical variables at the point of first use. For example:
      chomp(my $infile = <STDIN>);

    By the way, CountZero’s advice about double-quoting variables is explained in What's wrong with always quoting "$vars"?.

    (Also, please have a look at How do I compose an effective node title?.)

    HTH,

    Athanasius <°(((><contra mundum

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
      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 :)
        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

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.
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>){.


    Dave

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

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.
      That sounds useful. How do I do that?
        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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://985488]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2024-03-19 06:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found