Generalised Search-And-Replace
Specify patterns on the command line, but without worrying about quoting or escaping anything. Do search-and-replace over multiple files, at once. Do one thing, but do it well. #perl #script #search #replace [Source code]
My text editor of choice, vim
, is pretty good at searching and replacing text. On occasion, however, it seems lacking, usually for one of two reasons:
the text to be searched contains characters that need to be escaped—and just to make matters worse, in
vim
what you need to escape depends, e.g., on whether or not you use so-called “magic mode”, and other such wizardry…;the search and replace needs to be done over more than one file… which makes the process too cumbersome to be made in
vim
.
Now, at this stage, the cynical person will probably retort that I need a new text editor… but let us not listen to the naysayers! (Because what they actually mean is that I should be using an Integrated Development Environment (IDE), which I don’t do because… they all suck!)
What I did instead was to write a small Perl script, that basically takes an initial text, a replacement text, and replaces the former with the latter, either on a specific file, or in all files within a given directory, ending in a specific extension. In more detail, the script can be invoked in the following two ways (this is also shown when invoking the script with -h
):
$ /path/to/script -i '<original text>' -o '<replacement text>' -f <file name>
$ /path/to/script -i '<original text>' -o '<replacement text>' -d <dir name> -t <file extension>
The single most important thing to remember, when using this script, is the following:
To avoid involuntary Shell escaping, ALWAYS ENCLOSE ORIGINAL AND REPLACEMENT TEXTS IN **SINGLE** QUOTES!!
Doing that ensures that both <original text>
and <replacement text>
can contain spaces, backslashes, or other usually “problematic” characters, without need to quote/escape anything—the script will just work.
The first form will do the search/replace operation in the file named <file name>
, while the second will do it in all files in directory <dir name>
, having the extension <file extension>
. And this is basically it.
The -B
option. This extra nice to have is easy to explain with an example. Suppose you call the script with -i 'foo' -o 'bar'
. By default, it will replace (for example) foo_1
with bar_1
. To avoid this, i.e., to only replace “whole words”, pass the -B
option (for “word boundary”): then, the replacing will only take place when the string “foo” is surrounded by neither alphanumeric characters, nor underscores (_
).1 So in the previous example, foo_1
would not be replaced with bar_1
—but foo bar
would become bar bar
.
Setup
Take the code, save it in a file with .pl
extension (this is customary for Perl scripts), and give it executable permissions (chmod +x filename.pl
). This last part is optional, but if you don’t do it, then you can only invoke the script like this: $ perl filename.pl
, but not like this: $ ./filename.pl
. Then just use the script as explained above.
Last, but assuredly not least, the customary advice: using this script can result in large changes which, in case of errors, can be hard to undo. Hence, always backup your data before using it!
May 21, 2022.
[Update] May 28, 2022. The previous version, when modifying files in a directory, gave the total count of files found, not the total count of files that will actually be modified. This has now been fixed.