Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

RE: Replace across files (extreme newbie)

by mikfire (Deacon)
on May 23, 2000 at 22:45 UTC ( [id://14426]=note: print w/replies, xml ) Need Help??


in reply to Replace across files (extreme newbie)

For a minor tweak ( says the sysadmin, forever worried about users wasting his cycles ), try it this way
find . -type f | xargs perl -pi.bak -e 's/string x/string y/g'
Using the -exec flag will exec a perl for every file found. This can be slow and painful - the most expensive part of perl is the initial load. By piping to xargs, you start perl but once.

If you you have too many files to fit on one command line, you can modify the command like this:

find . -type f | xargs -n 255 perl -pi.bak -e 's/string x/string y/g'
which will cause xargs to call perl with 255 files each time.

Mik
Mik Firestone ( perlus bigotus maximus )

Replies are listed 'Best First'.
Re: RE: Replace across files (extreme newbie)
by Anonymous Monk on Oct 10, 2001 at 13:36 UTC
    As I find this find statement very handy but because I often
    forget commands I use seldom, I have put this useful thing
    into a useable script.
    Maybe a silly idea to execute a shell script invoking perl
    from a perlscript, but the target "Get it working" is reached :-)
    #!/usr/bin/perl -w # # replace_in_tree replaces stringx by stringy in files from current di +rectory # recursiveley and backups the original files to *.bak like # find . -type f | xargs -n 255 perl -pi.bak -e 's/string x/string y/g +' # does. # # Author : Sascha Wuestemann # License: Artistic GPL # eMail : Sascha.Wuestemann@epost.de use strict; sub usage { print <<EOF; usage: replace_in_tree <to_be_replaced> <replacement> <filematcher> replaces the string "to_be_replaced" with "replacement" from the current directory downwards the filetree in files matching filematcher, e.g. "*" or "*.html" example: replace_in_tree "Author: Bill Gates" "Author: Larry Wall" *.html EOF } sub exec_replace { open(GUN,"find . -name \"$ARGV[2]\" -type f | xargs -n 255 perl -pi.ba +k -e 's/$ARGV[0]/$ARGV[1]/g'|")|| die "can't execute shell commands:$ +!\n"; close(GUN)|| warn "couldn't close shell:$!\n"; } if (not $ARGV[2]) { usage; exit; } else { exec_replace } exit;



    --
    there are no silly questions
    killerhippy
      I think you are right: It's silly to execute this shell pipeline in a perl script.
      And the way you do it is even worse.

      If you want to put a complex shell command in a script, use a shell script, that's what it was made for.

      If you just want to execute a shell command in a perl script, use the system command. Unless you need the output of the command, then use backticks.

      Here is an example of a shell script doing the same as your perl script, but with much less resources:

      #!/bin/sh if [ $# -lt 3 ]; then echo " usage: replace_in_tree <to_be_replaced> <replacement> '<filematcher>' replaces the string "to_be_replaced" with "replacement" from the current directory downwards the filetree in files matching filematcher, e.g. '*' or '*.html' example: replace_in_tree 'Author: Bill Gates' 'Author: Larry Wall' '*.html' " exit fi find . -name "$3" -type f | xargs -n 255 perl -pi.bak -e 's/\Q$1\E/$2/ +g'
      Update: I forgot to mention that your script will probably fail.
      The third parameter (*.html) will be expanded by the shell, so perl will have the first filename in $ARGV2 and not the glob.
      Therefore I changed the usage to have the third parameter quoted.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (5)
As of 2024-04-24 22:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found