Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Can you teach a new dog an old trick?

by c (Hermit)
on Jul 28, 2001 at 20:29 UTC ( [id://100565]=perlquestion: print w/replies, xml ) Need Help??

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

I know this is a script written a thousand times over. Replacing a string with another string within a group a text files. I am betting that its such a command use for perl that its almost become a given how to write it. Here's my take on it. Suggestions on how to shorten it or better way to do it?

#!/usr/bin/perl -w use strict; my @array = glob("*.htm"); for my $i(@array) { open(FH, "$i"); open(NH, ">tmp"); while(<FH>) { $_ =~ s/string1/string2/g; print NH $_; } close(NH); close(FH); rename("tmp", $i); }

humbly -c

Replies are listed 'Best First'.
(jeffa) Re: Can you teach a new dog an old trick?
by jeffa (Bishop) on Jul 28, 2001 at 20:39 UTC
    perl -i.bak -pe 's/string1/string2/g' *.htm
    This changes all occurrences of the literal string, 'string1' with 'string2' in all .htm files and makes backups at the same time.

    jeffa

Re: Can you teach a new dog an old trick?
by bikeNomad (Priest) on Jul 28, 2001 at 20:40 UTC
    It's such a common idiom that the -p and -i command-line flags were invented to deal with it:

    #!/usr/bin/perl -wpi s/string1/string2/g;

    And then you'd run it as: myScript *.htm

    update: note that the contents of a script run with -p or -n are inside a loop. If you want to initialize anything before the loop, use a BEGIN or INIT block.

      This is not good...

      I tried to extend it to:

      #!/usr/bin/perl -wpi my $src = shift; my $dst = shift; s/$src/$dst/g;
      and it throws many many messages on me:
      Use of uninitialized value in substitution (s///) at /home/rj/bin/repl +ace line 4, <> line 38. Use of uninitialized value in regexp compilation at /home/rj/bin/repla +ce line 4, <> line 39. Use of uninitialized value in substitution (s///) at /home/rj/bin/repl +ace line 4, <> line 39. Use of uninitialized value in regexp compilation at /home/rj/bin/repla +ce line 4,
      (called "replace hallo hello tmp.txt")
      Then I looked at man perl what this switch -p does
      ok it was not there, so I looked at man perlrun and
      then I found the error (it tries to get $src and $dst in every
      loop. Well, I´m using my old replace script now again...
      #!/usr/bin/perl my $src = shift; my $dst = shift; print "Replace >$src< with >$dst<.\n"; $dst =~ s/\\n/\n/g; $dst =~ s/\\t/\t/g; foreach $file (@ARGV) { my $file2 = "/tmp/$file.".$$; print "replacing in File: $file...\n"; print "$file2\n"; open HANDLE, $file or die "$file: $!"; while(<HANDLE>) { $zeile .= $_; # Zeile von Datei einlesen } close HANDLE; $zeile =~ s/$src/$dst/gs; open HANDLE, ">$file2"; print HANDLE $zeile; close HANDLE; $zeile = ''; system("mv $file2 $file"); }
      Its ugly and unelegant and made 1996, but it works. :-)

      Ciao

        You need to use a BEGIN block, like so:

        #!/usr/bin/perl -wpi BEGIN { ($src,$dst)=(@ARGV); } s/$src/$dst/g;
Re: Can you teach a new dog an old trick?
by Chady (Priest) on Jul 28, 2001 at 20:39 UTC
    perl -pi.bak -e "s/string1/string2/g" *

    run this and it will open all files in the current directory with the inplace file edit -i and files are backed up to .bak extensions, the -p assumes that there is a while loop over the file so all you need to do is run the substitution within a -e switch and you're done with it.

    Update: I stole from jeffa's post that you should have *.htm instead of * so it won't eat all the files


    He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

    Chady | http://chady.net/
Re: Can you teach a new dog an old trick?
by Anonymous Monk on Jul 28, 2001 at 23:34 UTC
    Well, it's not all in perl. This one uses the power of the shell and saves a backup copy. I use it routinely to edit system files on 100s of machines quickly and easily.

    perl -i.bak -pe 's/string1/string2/g' *.htm

    doug

Re: Can you teach a new dog an old trick?
by Anonymous Monk on Jul 29, 2001 at 02:28 UTC
    why not simply the command line usage--- perl -p -i -e 's/oldstring/newstring/g' filename(s)
Re: Can you teach a new dog an old trick?
by John M. Dlugosz (Monsignor) on Jul 30, 2001 at 02:49 UTC
    Other's have shown how to use -i, -p, -n, etc. But I wanted to point out another issue.

    I use a program called tcgrep, which is a grep clone written in Perl by Tom Christenson. I've updated it to do its own globbing in Windows platforms. I don't know if that does replacements... but, being such a common thing, I'll bet an egrep or whatever exists too, that does this with lots of fancy and subtle features.

Re: Can you teach a new dog an old trick?
by Anonymous Monk on Jul 29, 2001 at 23:22 UTC
    Use the command-line:
    perl -pi.bak -e 's/string1/string2/g' *.htm
    Use double quotes on Windows.
Re: Can you teach a new dog an old trick?
by Anonymous Monk on Jul 30, 2001 at 17:29 UTC
    #!/usr/bin/perl -p -i
    s/string1/string2/g;

    run this as
    ./script *.htm
Re: Can you teach a new dog an old trick?
by mischief (Hermit) on Jul 30, 2001 at 23:19 UTC

    The only change I would make is to add this line:

    die "file already exists\n" if -e "tmp"

    at the top, just to avoid clobbering any existing tmp files or directories or whatever.

      Could the code to recurse through sub directories, processing all the *.html be added in only a few lines?
        You want to use File::Find to deal with that.

        use strict; use File::Find; find( sub { return unless -f $_ and /\.html?$/; # do your funky thang }, shift || '.' );

        That is, recurse starting from the directory given on the command line, or the current directory if nothing is specified. Then, only for directory entries that are files whose extension is .htm or .html, do whatever makes you happy.

        --
        g r i n d e r
        My dirty code for descending subdirectories used the unix find command to generate a list of files to be acted on. In my case, to chmod files.

        %perl -e '@list = `find . -name "*.htm"`; foreach (@list) {`chmod 644 +$_`}'

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-25 18:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found