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
vimwhat 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
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
$ /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.
-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)
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
foo bar would become
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.
I check for underscores because it is common, in some programming languages, to name variables
like_this_var. In any event, the characters that are taken to constitute a word boundary can be modified, by changing the
$_REGEX_ALPHANUM_BORDERvariable, in the script’s source code.↩︎