Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Changing data in one directory

by Anonymous Monk
on Jul 31, 2003 at 13:40 UTC ( [id://279572]=perlquestion: print w/replies, xml ) Need Help??

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

I am having trouble trying to figure out how to change alot of data in files located in One directory. Can someone help me solve this problem?
$files = "/perl/bin/ThisDirectoryHere"; opendir(DIR,$files) || die "Can not open directory: $!"; @files = grep(!/^\.+$/, readdir(DIR)); close(DIR); $ct = 0; #I need to open each file and change oldword to newword for(@files) { s/oldword/newword/gi; } print "\nTotal Changes = $ct\n";

Replies are listed 'Best First'.
Re: Changing data in one directory
by tcf22 (Priest) on Jul 31, 2003 at 13:54 UTC
    How about something like this.
    use strict; my $files = "/perl/bin/ThisDirectoryHere"; opendir(DIR,$files) || die "Can not open directory: $!"; my @files = grep(!/^\.+$/, readdir(DIR)); close(DIR); my $ct = 0; #I need to open each file and change oldword to newword for(@files) { #Read File open(IN, "$files/$_") || die "Can't open $_: $!\n"; my @lines = map {$ct += s/oldword/newword/gi;$_} <IN>; close(IN); #Write File open(OUT, ">$files/$_"); print OUT @lines; close(OUT) } print "\nTotal Changes = $ct\n";
Re: Changing data in one directory
by l2kashe (Deacon) on Jul 31, 2003 at 14:16 UTC

    You state that you want to alter the contents of the files, yet you are not opening them to work on them after you have collected your file listing. Here is one way to alter the contents of each file, but the regex is far to simple in this case, and will probably alter more than it should.

    my $base = '/perl/bin/thisdir'; my $count; opendir(BASE, $base) or die "Cant open $base: $!\n"; for (grep( !/^\./, readdir(BASE) )) { open(IN, "$base/$_") or warn "Cant access $_: $!\n" and next; while (<IN>) { $count += s/old/new/gi; } close(IN); } closedir(BASE); print "Total changes: $count\n";

    Looking at the code you presented, if you are attempting to actually alter the file names in the directory, you could have the following within the for( readdir ) loop

    # snip.. ( my $newfile = $_ ) =~ s/old/new/; rename("$base/$_", "$base/$nwewfile"); # snip..

    Update: Added counting to loop

    use perl;

Re: Changing data in one directory
by Zaxo (Archbishop) on Jul 31, 2003 at 14:12 UTC

    The glob function will exclude dotfiles for you. It would be a good idea to test that each filename is a regular file, and is readable and writable to you. There is a handy set of run flags in perl for sed-like operations like this, so I'll show how to call up a second perl process to do the work,

    my $dir = "/perl/bin/ThisDirectoryHere"; my @files = grep { -f and -r _ and -w _} glob "$dir/*"; system '/usr/bin/perl', '-pi', '-e', 's/oldword/newword/gi', @files and die $?;
    That omits your change counting. The odd looking error handling in system...; is because of the inverted logic of its return value.

    The alternative is to set up a loop on @files as you have, opening each to read and a new file to write. Read, substitute, write, and when done, rename the new file to the old name. File locking (flock) may be advisable.

    After Compline,
    Zaxo

Re: Changing data in one directory
by Cine (Friar) on Jul 31, 2003 at 14:12 UTC
    find /perl/bin/ThisDirectoryHere -type f | xargs perl -i -pe 's|oldwo +rd/newword/gi'
    You loose the number of changes, but is that important?

    T I M T O W T D I

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (3)
As of 2024-04-26 00:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found