Human Readable  

 

     
   
     

Global Search and Replace

© Copyright Darrell Anderson.

(Autumn 2008)

In the Windows world there are few options for globally searching files and replacing one string of text with another. Or more complicated, a block of text with something else. Although regular expressions remain mostly a mystery to me, for a few years I got by using PowerGrep, a tool I recommend for any Windows user.

Migrating to Slackware left me without PowerGrep. Of course there are the typical command line tools of grep, sed, and awk. Those tools are challenging to use and master, however. For some time I have been aware of KFileReplace. On the surface the tool seems the equivalent of PowerGrep. Yet this is not the case.

I wanted to delete a multi-line block of text that is similar within a few hundred files. Delete, not replace. Of course, a deletion is a subset of replacing. By deleting, I mean searching but replacing the block of text with nothing.

Although the size of each multi-line block was the same, the text within the blocks was not exactly the same in each document. Therefore I needed to use regular expressions to represent the text between known strings of text.

Replace something with nothing. This seems so simple an idea — even the most basic of text editors do this.

Try as I might, I found no way to replace something with nothing. KFileReplace would only perform a search when the replace field was empty.

Eventually I discovered the “.*” wild card to create a regular expression search string that KFileReplace accepted. I also had to use the backslash to escape almost every non alpha-numeric character. Fortunately for me, the line of text preceding the block of text I wanted to delete was the same in each document. Therefore I used that line as my replacement string.

Therein lies the conundrum. If I left the KFileReplace replace option empty, implying replace something with nothing, then KFileReplace seems limited to performing only a search. The replace button is ghosted if the replace option remains empty. Perhaps there is a special string I need to enter in the replace text box that represents “replace with nothing”?

The next time I need to perform a global deletion like this I might not be so fortunate to have at least one adjoining line of text that is the same in each document.

KFileReplace has much potential but seems terribly neglected by the KDE developers. The associated KFileReplace handbook has not been updated in four years and contains no examples. I have almost no clue about the full regex syntax KFileReplace uses. I got lucky this time using the “.*” wild card expression to represent text between two known strings of text.

Seeing these limitations, I decided to search for command line examples to search and replace text. I tried several times to create a simple shell script using sed where I could pass parameters or even manually edit variables. The sed tool kept refusing to accept variables. Then I found an awk example:

awk '{gsub(a,b);print}' a="$VAR1" b="$VAR2" $FILE1 > $FILE2
mv -f $FILE2 $FILE1

That seemed to work. Could I find a similar example using sed? The basic syntax seemed to require the following:

sed -i -e 's/$VAR1/$VAR2/g' $FILE1

Yet that always failed. sed refused to accept the variables. Then through an online discussion, one person suggested using double quotation marks rather than single:

sed -i -e "s/$VAR1/$VAR2/g" $FILE1

sed then performed the replacement without a hitch. I don’t know why double marks work and single do not. Probably has something to do with how bash parses, escapes, and interprets everything.

Next, back to my original problem: how to use sed to traverse multiple lines? That is, replace something with nothing. I found a mini how-to that explained this syntax:

sed "/$VAR1/,/$VAR2/d" $FILE1

I defined $VAR1 as the first line I wanted to delete. I defined $VAR2 as the last line I wanted to delete. Worked great but because the document contained empty line breaks to separate paragraphs, I was left with a double blank line.

I then found the following example to delete double blank lines:

sed "/./,/^$/!d"

I then tried the following:

sed "/$VAR1/,/$VAR2/d" $FILE1 | sed "/./,/^$/!d"

That worked great but the output was to stdout not actual inline replacement. I next tried:

sed "/$VAR1/,/$VAR2/d" $FILE1 | sed "/./,/^$/!d" > $FILE2

cat $FILE2

Worked great again. Next I tried:

sed -i "/$VAR1/,/$VAR2/d" $FILE1 | sed -i "/./,/^$/!d" $FILE1
cat $FILE1

The same person who helped me previously suggested I could shorten that command:

sed -i -e "/$VAR1/,/$VAR2/d" -e "/./,/^$/!d" $FILE1
cat $FILE1

That seems to be the successful end of this particular sed lesson for me.

I remain convinced KFileReplace has much potential and is sadly neglected.

Finis.

Next: Updating Firmware

Table of Contents