Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

OK, I'm trying to modify a text file based on user input (one variable). The user input stuff works (thanks to suggestions here), but the file input/output keeps not working. The file exists and is populated, and the search pattern is in there, but it's still not modyfying my file. I've got STDERR redirected to a file, but it only gives me the following error when I'm trying to "use Strict;": "Can't use string ("c:\blah.txt") as a symbol ref while "strict refs" in use at c:\console.pl line 20, <STDIN> line 1." No other errors. Without "use Strict;" and removing the "my" references, I get no errors, but it still doesn't work.

Question no. 2: after the file read/write works, I need to generalize the search pattern - ie, instead of "serverport 111" I need it to search for "serverport until the newline". I was thinking something like s/serverport*$/serverport $port\n/ should work, but I'm just checking.

Thanks for your help.

Glenn

#!/usr/bin/perl use Win32::Console; use strict; open(STDERR, ">error.log"); my $con = Win32::Console->new(); $con->Mode(ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_ +INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_ +EOL_OUTPUT); $con->Display; $con->Write("Please enter the agent ID number: "); chomp(my $port = <STDIN>); $con->Write("The port number to use is $port.\n"); #Debug stuff, this +works open(CONFIG, "+<", "c:\\blah.txt" or die "Can't open blah.txt: $!"); my @configfile = <CONFIG>; foreach my $configfile (@configfile) { $configfile =~ s/serverport 111$/serverport $port\n/; print CONFIG $configfile; } close(CONFIG); close(STDERR);

Replies are listed 'Best First'.
Re: modifying a text file on Win32
by dvergin (Monsignor) on Aug 13, 2001 at 06:01 UTC
    You have a misplaced parenthesis. This line:

    open(CONFIG, "+<", "c:\\blah.txt" or die "Can't open blah.txt: $!");

    should look like this:

    open(CONFIG, "+<", "c:\\blah.txt") or die "Can't open blah.txt: $!";

    The   'or die...'   bit is not part of the   open(...).

    Update: The suggestion of John M. Dlugosz regarding the regex modifier is also promising (depending on the nature of the data). But /m is the one you want to explore, not /s.

    These are often confused:
            /m   allows ^ and $ to match embedded \n
            /s   allows . (dot) to match newlines
     

Re: modifying a text file on Win32
by chipmunk (Parson) on Aug 13, 2001 at 06:43 UTC
    You've opened your file for reading and writing, which is good, but after you read in the file, you don't seek back to the beginning. So, you're appending the modified lines at the end of the existing contents.

    The easiest way to modify a file in place is probably to use Perl's nifty in-place editing feature. Here's one way of doing it:

    #!/usr/bin/perl -i.bak # in-place editing; save the original file with a .bak extension use Win32::Console; use strict; open(STDERR, ">error.log") or die "Can't open error log: $!\n"; my $con = Win32::Console->new(); $con->Mode(ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); $con->Display; $con->Write("Please enter the agent ID number: "); chomp(my $port = <STDIN>); $con->Write("The port number to use is $port.\n"); #Debug stuff, this +works { local @ARGV = "c:\\blah.txt"; # set up a temporary @ARGV for in-place editing while (<>) { s/serverport 111$/serverport $port/; print; } }
    All you have to do is use the -i switch and put the name of the file(s) to change in @ARGV. Then you can just read in lines with <>, modify them, and print them back out.

    See perlrun for more about Perl's -i command line switch.

      Thanks for the suggestions. I'm still getting the same error with your code as I mentioned in my post below - can't find c:\blah.txt, no such file or directory. But the file is definitely there...Maybe it's a Win32 thing??

      Thanks,

      Glenn

        Just checking, the file really is in the root directory of the C drive?

        You might try specifying the file simply as 'blah.txt' (without any path), chdir-ing to the directory containing 'blah.txt', and running your script from there.

Re: modifying a text file on Win32
by John M. Dlugosz (Monsignor) on Aug 13, 2001 at 06:02 UTC
    Look at what the /m and /s options do to your pattern replacement. Your problem may be that your file contains multiple lines, but by default the s// assumes it is a single line. --John
Re: modifying a text file on Win32
by Anonymous Monk on Aug 13, 2001 at 06:57 UTC
    Duh!! Thanks!! Now I've moved the parenthesis, and I'm getting the following error now from STDERR: "Can't open blah.txt: No such file or directory at c:\console.pl line 19, <STDIN> line 1." Which is odd because I'm looking at the file right now - I'm testing this on Windows 98, and the file isn't set to Read Only, and I've tried closing blah.txt completely before running the script. I've tried moving the file from c:\blah.txt to c:\perl\bin\blah.txt (I'm invoking the file from the command line from c:\perl\bin via "perl c:\console.pl"), but it doesn't seem to matter.

    Any ideas??

    Thanks,

    Glenn

      First you can drop the Windows centric paths and use / instead of \ Perl will supply Windows with the correct path delimiters for the platform automagically changing / into \ as required.

      The path is not however your problem. As you open the file for read/write you need to remember that at the end of the read you are at EOF so you need to seek the begining of the file and also truncate it to 0 unless you want to run the risk of getting crap at the end. I have added as die to the print CONFIG (remove the seek and truncate and you will get the error). This runs fine now. BTW don't open STDERR ">error.log" without including some path info. Even ./ for the current working directory makes it obvious where to look for this file. Also when you read data in from a file the newlines will still be there so you don't need to add more in your substitution

      open(CONFIG, "+<c:/blah.txt" ) or die "Can't open blah.txt: $!"; my @configfile = <CONFIG>; seek CONFIG, 0, 0; # go to start of file for overwrite truncate CONFIG, 0; # get rid of old file foreach my $configfile (@configfile) { $configfile =~ s/serverport 111$/serverport $port/; print CONFIG $configfile or die $!; } close(CONFIG); close(STDERR);

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

        Thanks for your suggestions. However, using c:/blah.txt still gives me the "can't find file" error. I've also tried variations like the filename in all caps, capitalizing the drive letter, even trying /blah.txt, thinking perhaps perl will translate that to the root of my only hard drive. No such luck.

        Other thoughts??

        Thanks,

        Glenn

Re: modifying a text file on Win32
by Anonymous Monk on Aug 13, 2001 at 16:55 UTC
    Solved!! Thanks to all. I'm going to go with chipmunk's solution as it seems to me the most logical, but this thread has been most educational. BTW, my problem with the file opening turned out to be my mistake and/or a windows glitch - on closer inspection in DOS it turns out the file had gotten named "blah.txt.txt", hence of course "blah.txt" doesn't exit. A simple renaming and that's fixed.

    Thanks again,

    Glenn