rjsaulakh has asked for the wisdom of the Perl Monks concerning the following question:
i have a file called edit where a list of file paths is given and in each of the file given in the path i need to match for multiple lines and delete them if they are there and save the file with the same file name . i have written a piece of code that works fine individually when $path is set to individual file but when i have file named edit contains multipe file path this script doesnt seem to do anything when it reaches the internal while loop .
please let me know if i m doing some wrong
#!/usr/bin/perl
#edit contains the complete path of the files to be edited
my $path = "/home/rjs/heena/edit" ;
#geting a file handler
open(FL, "$path");
#getting all the file names in the @array so that i can process the fi
+le one by one
my @array = <FL>;
while ( my $array = shift @array)
{
my $file = $array;
@ARGV = ($file);
# $INPUT_RECORD_SEPARATOR
$/="";
# $INPLACE_EDIT
$^I=".bak";
print "all fine \n ";
while(<>)
{
# nothing seems to happen after this piece of code
s/CONFIDENTIAL(.*?)own\s+risk/ /sm;
print ;
}
}
a sample view of the file
/*********************************************************************
+********/
/*
+ */
/* Copyright (c) 1996 - 2003
+ */
/* Campaco Systems, Inc.
+ */
/*
+ */
/* All Rights Reserved
+ */
/*
+ */
/* CONFIDENTIAL and PROPRIETARY --
+ */
/* No Dissemination or use without prior written permission
+ */
/*
+ */
/* Permission to use, copy, modify, distribute and sell this software
+and */
/* its documentation for any purpose is hereby prohibited, unless gran
+ted */
/* an explicit permission from Campaco Systems, and provided that the
+above */
/* copyright notice appears in all copies and that both that copyright
+ */
/* notice and this permission notice appear in supporting documentatio
+n. */
/*
+ */
/* Campaco Systems makes no representations about the suitability of t
+his */
/* software for any purpose.
+ */
/* It is provided "as is" without express or implied warranty. Modific
+ation */
/* of the code is allowed at the modifier's own risk.
Re: in place editing a list of files
by liverpole (Monsignor) on Jan 07, 2007 at 17:43 UTC
|
Hi rjsaulakh,
A lot of suggestions for you:
- Use strict and warnings to make your life easier.
- Indent your code to better show the control flow
- Use the 3-argument form of open, and always check for success or failure.
- Always close files as soon as you're done reading from them.
- Use chomp (or chop) to remove the trailing newline, especially if the line represents a filename.
- Use foreach to easily iterate through lists
Putting them all together, you get the simplified:
#!/usr/bin/perl
# Always use these
use strict;
use warnings;
# Edit contains the complete path of the files to be edited
my $path = "/home/rjs/heena/edit" ;
# Getting a file handler (and test for success/failure!)
open(FL, "<", $path) or die "unable to open data file '$path' ($!)\n";
# Getting all the file names in the @array so that i can process the
# file one by one
chomp(my @array = <FL>);
# Close the data file
close(FL);
# Process each file
foreach my $file (@array) {
next if ($file =~ /^\s*$/); # Skip blank lines from datafile
open(FILE, "<", $file) or die "unable to open file '$file' ($!)\n"
+;
while(<FILE>) {
s/CONFIDENTIAL(.*?)own\s+risk/ /sm;
print;
}
close(FILE);
}
s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
| [reply] [Watch: Dir/Any] [d/l] |
|
You seem to have missed the in-place edit part. And the part where the regex needs to affect multiple lines at once.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
Hi rjsaulakh,
As ysth pointed out, my code was not doing the in-place editing part, nor the multi-line edit. But those are quite easy to do.
Here's a modified example that should work for you.
Notice that the datafile can contain blank lines or commented-out lines, which are skipped (eg. # testfile).
Notice, too, that the input file, once it's read and processed, is being written to, so it's REALLY an in-place edit.
Warning: Since it's doing in-place edits, be careful to have a backup copy of any files that you need to keep the original of!
Here's the code:
#!/usr/bin/perl
+
# Always use these
use strict;
use warnings;
+
# Edit contains the complete path of the files to be edited
my $path = "/home/rjs/heena/edit" ;
+
# Getting a file handler (and test for success/failure!)
open(FL, "<", $path) or die "unable to open data file '$path' ($!)\n";
+
# Getting all the file names in the @array so that i can process the
# file one by one
chomp(my @array = <FL>);
+
# Close the data file
close(FL);
+
# Process each file
+
foreach my $file (@array) {
next if ($file =~ /^\s*(#|$)/); # Skip blank/commented lines
process_file($file); # Process file
}
+
+
# Subroutines
sub process_file {
my ($file) = @_;
+
$/ = ""; # Read entire file as a single line
my $fh; # Declare file handle (better than using globals)
+
# Read the file
open($fh, "<", $file) or die "unable to read file '$file' ($!)\n";
$_ = <$fh>;
close($fh);
+
# Apply the change
s/CONFIDENTIAL(.*?)own\s+risk/ /sm;
+
# Write the file back TO THE SAME FILENAME
open($fh, ">", $file) or die "unable to write file '$file' ($!)\n"
+;
print $fh $_;
close $fh;
}
I made the file-processing into a subroutine for clarity, but you could do it within the loop if you wanted to, naturally.
s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: in place editing a list of files
by ysth (Canon) on Jan 07, 2007 at 18:38 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
#edit contains the complete path of the files to be edited
my $path = "./edit" ;
#geting a file handler
open(FL, "$path");
#getting all the file names in the @ARGV so that i can process them
chomp(@ARGV = <FL>);
# $INPUT_RECORD_SEPARATOR
$/="";
# $INPLACE_EDIT
$^I=".bak";
while(<>)
{
s/CONFIDENTIAL(.*?)own\s+risk/ /sm;
print ;
}
It's possible you are having file permission problems, in which case, you are probably better off not relying on $^I but instead explicitly renaming each file and opening the old and new names, checking each operation for success and giving a meaningful error message on failure. | [reply] [Watch: Dir/Any] [d/l] |
|
readline() on closed filehandle FL at C:\Documents and Settings\liverp
+ole\edit.pl line 13.
or something similar. What's even worse is that, at least on my Windows box, the program doesn't terminate, forcing you to ^C to get out of it.
That's why I was suggesting the error-checking when opening files.
s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
I can only suggest you run it under the debugger, examining all variables as you go and seeing where things go differently than you expect. Alternatively, rewrite to not use the empty <> operator and explicitly do every open, rename, print, and close, checking for errors after each one.
| [reply] [Watch: Dir/Any] |
Re: in place editing a list of files
by davidrw (Prior) on Jan 07, 2007 at 17:09 UTC
|
doesn't directly address your code issues, but here's a different approach that should do what you want from a bash prompt:
for f in `cat /home/rjs/heena/edit` ; do
perl -i.bak -0777 -pe 's/CONFIDENTIAL(.*?)own\s+risk/ /s' $f
done
Update: shell-independent method: perl -i.bak -0777 -pe 's/CONFIDENTIAL(.*?)own\s+risk/ /s' `cat /home/rjs/heena/edit`
If the 'edit' file contains a list of directories (i wasn't entirely sure from your post), then:
for d in `cat /home/rjs/heena/edit` ; do
perl -i.bak -0777 -pe 's/CONFIDENTIAL(.*?)own\s+risk/ /s' $d/*
done
See perlrun for info on the various switches (the -0777 causes a slurp). | [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] [d/l] |
|
depends what "incorporated" means ..
does this need to be invoked from inside another script? if so obviously just can't copy/paste verbatim (could dump it in a system call, though maybe not ideal method) ..
or does this just need to be called right before/after another perl script? if so, could just wrap the two calls in a shell script ...
otherwise, write a sub that sets $^I, @ARGV, $/, and runs the loop that -n or -p does (see perlrun)
| [reply] [Watch: Dir/Any] |
|
|