hypernatic.net
03-11-2002, 11:25 AM
Hi,
I tried to make a perl script that opens a file, searches for a string, and if found changes the string to something else and writes that to the file...
However, this fails... any ideas?
#!/usr/bin/perl
open (FILE,"./FILE.txt");
@FILE= <FILE>;
close (FILE);
foreach $line(@FILE) {
if($line=~/\STRING//gi) {
print "FOUND!";
$line="STRING2";
}
else {
print "NOT FOUND!";
}
}
open (FILE,"./FILE.txt");
print FILE @FILE;
close (FILE);
Tim Greer
03-11-2002, 02:57 PM
Originally posted by hypernatic.net
Hi,
I tried to make a perl script that opens a file, searches for a string, and if found changes the string to something else and writes that to the file...
However, this fails... any ideas?
Hi,
Note: This will not be posted in a very readable-friendly format, due to the stripping of white space in the WHT posts, but... First of all, you should check your calls. Also, you shouldn't (usually, depending on the file size and contents) read everything into an array -- that could potentially take up a lot of memory and isn't very efficient (read it in line by line instead of just throwing it all into one (potentially) big array) -- you should use while (<FILEHANDLER>) instead and code this differently, but for your code example, I'll stick with this way you have it now. Your other problems are that you changed the $line variable, but you aren't doing anything with it, and you're only just writing the FILE array again into the new file. Finally, the new file isn't being opened for writing and you put it as \S in the regex search, which is equal to "Not a space character", just as \s would "equal a white space character". You also put in a search and replace function by using the 3 operators ///, and that's not for matching only (i.e., if you put is as if ($line =~ s/STRING//gi), it would replace "STRING" with nothing. You have it as if ($line =~ /\STRING//gi), which will create a divide by zero error. It needs to be if ($line =~ s/STRING/NEWSTRING/gi), or if ($line =~ /STRING/gi).
Try this:
#!/usr/bin/perl
open (FILE,"./FILE.txt") or die "Can't open file FILE.txt for read: $!\n";
@FILE= <FILE>;
close (FILE) or die "Can't close file FILE.txt on read: $!\n";
$i = 1;
foreach $line (@FILE) {
if ($line =~ /STRING/gi) {
print "FOUND on line $i!\n";
$FILE[$i - 1] = "STRING2\n";
} else {
print "NOT FOUND on line $i!\n";
$FILE[$i - 1] = $line;
}
$i++;
}
open (FILE,">./FILE.txt") or die "Can't open file FILE.txt for write: $!\n";
print FILE @FILE;
close (FILE) or die "Can't close file FILE.txt on write: $!\n";
Also, instead of using if ($line =~ /STRING/gi) and $FILE[$i - 1] = "STRING2\n"; on two lines, you can combine them and save some time:
$i = 1;
foreach $line (@FILE) {
if ($line =~ s/STRING/STRING2/gi) {
print "FOUND on line $i!\n";
} else {
print "NOT FOUND on line $i!\n";
}
$FILE[$i - 1] = $line;
$i++;
}
Or, you can cut that down more, if you don't need the information printed.
$i = 1;
foreach $line (@FILE) {
$line =~ s/STRING/STRING2/gi;
$FILE[$i - 1] = $line;
$i++;
}
Keep in mind, the original way will take a line and replace "This is a string right here!" with "STRING2". With the code I put above here, it will replace only the part of the string you want to replace with the new part. I.e., it will then say "This is a STRING2 right here!". I'm not sure what you want to do, but that might do it, or you might want to put in some boundary conditionals to suit it to meet whatever needs you have. There are better ways to do this, but this will give you a workable example of what you're currently trying to get going. I hope the reasons are clear, but I can explain them if you want -- and if you're wondering, there are about 20+ different ways to do this and I just choose the one I thought would probably make the most sense to you by looking at your example code.
Tim Greer
03-11-2002, 03:16 PM
Oh, here's a simpler, smaller way to do it too, as described above. This is another example, even though you can definitely do it a lot of other ways. Although this builds an array to write, it doesn't need to read in a potentially very large array first, then process it and rebuild it (or a new one).
#!/usr/bin/perl
open (FILE,"./FILE.txt") or die $!;
while (<FILE>) {
s/STRING/STRING2/gi;
$new[$line |= 0] = $_;
$line++;
}
close (FILE) or die $!;
open (FILE,">./FILE.txt") or die $!;
print FILE @new;
close (FILE) or die $!;
I hope that opens your mind a little to some more ideas.
bitserve
03-11-2002, 03:25 PM
I just do it like this:
perl -pi -e 's|foo|bar|g' `find . -type f`
Tim Greer
03-11-2002, 03:27 PM
Originally posted by bitserve
I just do it like this:
perl -pi -e 's|foo|bar|g' `find . -type f`
Or just use sed at that point.
priyadi
03-12-2002, 12:57 AM
Originally posted by bitserve
I just do it like this:
perl -pi -e 's|foo|bar|g' `find . -type f`
Or, if you had a lot of file:
find -type f | xargs perl -pi -e 's|foo|bar|g'
Tim Greer
03-12-2002, 02:36 AM
I think that before we get too geeky about how to do this and start posting Schwartz-like command line alternatives, that we should assume this user's question about why the script didn't work, is answered. I wouldn't want to risk confusing someone with any one-liner command line stuff -- and I came to that conclusion before I posted some really genius command line stuff too (really, I promise. :)
Lawrence
03-12-2002, 04:10 AM
As they say in Perl, "There's more than one way to confuse someone".
Or was it "There's more than one way to do it"?
:D