CleanCode Perl Libraries |
Home | Perl | Java | PowerShell | C# | SQL | Index | Tools | Download | What's New |
Multi-Lingual Library | Maintainability | ||||||||||||
Perl | Java | JavaScript | Certified Class |
Testable Class |
Standalone Mode |
Diagnostic Enabled |
replace.pl - Modify multiple files, including recursive directory search.
replace.pl [options] targetRegExp replaceRegExp {files or folders}...
replace.pl [options] {targetRegExp replaceRegExp}... FILES {files or folders}...
-T do not restore timestamp
-N do not make .cmp backup files
-l list files which would be updated but don't change files
-L list matched text within each file but don't change files
-q quiet mode; do not report on files that did not change
-e ext process only files ending in ".ext"
-m regexp /m modifier (match ^ and $ at lines within block)
-s regexp /s modifier (allow . to match newlines within block)
-b create auto-block (-ms and extend targetRegExp to full lines)
-h help
-H longer help (manual page)
File::Find, File::stat, Getopt::Std, Pod::Usage, Data::Handy, File::Handy
Modify all files specified on the command line. Any named directory will be examined recursively. Each file is examined for the regular expression targetRegExp
. The targetRegExp
is changed to replaceRegExp
, if found, and the original file is saved as filename.cmp
. After the change, the timestamp of the file is reset to match the original unless the -T option is specified.
As you will note in the Synopsis above, there are 2 variants of the command syntax. You may specify either a single target/replacement pair with any number of files/folders or--by adding the FILES marker for separation--you may specify multiple target/replacement pairs with any number of files/folders.
The standard mode is line-at-a-time for best use of resources. However, if you wish to operate on a block, use the -m
(multiple-line) and/or -s
(single-line) regular expression modifiers. These activate the s
and m
modifiers, respectively, for the regular expression substitution. Using either -m
or -s
necessitates reading the entire file at one time, so huge files might have issues. If you had this text, for example...
line before
- - start superfluous block --
a
b
c
- - end superfluous block --
line after
...use this command...
replace.pl -ms "[^\n]*start superfluous.*end superfluous[^\n]*\n" "" file
...to reduce it to...
line before
line after
The leading [^\n]*
and trailing [^\n]*\n
give you a clean excision at line boundaries. The -b option is a shortcut for the combination of -ms with this prefix and suffix added to the pattern.
Either the targetRegExp
or replaceRegExp
are string literals by default, but either may reference a file instead by using the notation file:
filepath. In that event, the contents of the file are read as a single string and used as the argument.
The operands may use standard backreferences in order to copy a phrase from the matched text specified by targetRegExp
to the result text specified by replaceRegExp
. Example: With targetRegExp of "(stuff.*)=foo.*bar" then "$1=other" may be used to retain the first backreference.
The replaceRegExp
string may also use "\n" and "\t"; these are replaced with the actual characters they represent (newline, tab) before being used.
replaceRegExp
may use embedded variables [FILENAME]
or [PATHNAME]
to substitute the appropriate string during processing. [PATHNAME]
represents a complete file path, while [FILENAME]
is the file name without the path. So if you are processing a multi-level directory and want to change the string"foobar" to "foobar in file" where file is the full path, use a command like this:
replace.pl "foobar" "foobar in [PATHNAME]" .
The "." at the end of the command represents the current directory and all of its children since processing is recursive.
One should, of course, exercise care when updating a large number of files. The -l
and -L
options can assist quite a bit with this. Use -L
to see exactly what is matched without making any changes. For example, in each CleanCode source file I began with a version of this line in a generic header:
# @doc = xxx
where I was using "xxx" as a marker to be filled in with the path to this file's API. To change the "xxx" to the full path of the source file, I then started with:
replace.pl -e pl -L "(@doc = )xxx" "$1[PATHNAME]" .
The result shows the lines that would be changed for each file, as in:
api/perl/bin/a.pl...
# @doc = api/perl/bin/a.pl
api/perl/bin/b.pl...
# @doc = api/perl/bin/b.pl
Since the [PATHNAME]
marker is used, the value of that field is shown dynamically updated for each file.
Next changing the -L
to -l
shows which files will be changed rather than the matches, just to confirm it agrees with what I expect:
api/perl/bin/a.pl...will be changed
api/perl/bin/b.pl...will be changed
Now confident in the outcome, I remove the -l
to proceed with the changes.
What I really want, however, is "@doc = /api/perl/bin/replace.html" rather than "@doc = /api/perl/bin/replace.pl". (That is, I now need to change the file extension from pl
to html
.) So I run this second invocation to complete the task:
replace.pl -e pl "(@doc\s+=\s+/api/perl/bin/\w+)\.pl" "$1.html" .
Use the -e
option to filter only files matching a particular extension. The above example shows how this is done for files ending in pl
. Note that in no case can you operate on .cmp
files since that is the extension reserved for a copy of the original file when changes are made. Hence, whether you use -e
or not, files ending in .cmp
will never be processed.
None
Michael Sorens
$Revision: 8 $ $Date: 2006-12-19 21:13:43 -0800 (Tue, 19 Dec 2006) $
CleanCode 0.9
Home | Perl | Java | PowerShell | C# | SQL | Index | Tools | Download | What's New |
CleanCode Perl Libraries | Copyright © 2001-2013 Michael Sorens - Revised 2013.06.30 |