emanic
emanic

Reputation: 151

Match and replace string with sed in makefile

I want to search through a bunch of MD and HTML files for a line that begins with "id" and replace any instances of a string "old" with the string "new". I had this working from the command line with the following.

find \( -name '*.md' -o -name '*.html' \) -exec sed -i '/id:/s/old/new/g' '{} \;

However, I need to run the command from a Makefile. I have never done anything with make before. When I drop this same command into the Makefile and try to execute it from there, it fails. That's when I realized how little I know about make because I naively thought if it worked from the command line it would work from make. I was wrong. So I was looking in this Makefile for some examples of sed commands that do something similar and I came up with the following. This does not error out but it also does not do anything to my files. So, I am at a loss. Any help is appreciated!

switch_old_for_new:
    find \( -name '*.md' -o '*.html' \) -exec sed -i 's#^\(id: \)$(OLD)#\1$(NEW)#' '{}' \; 

NOTE: as you can probably see, I need to be able to pass in two actual values for "old" and "new" from the command line, so I also need to have variables in the sed. So I would execute it like this:

make switch_old_for_new OLD=old NEW=new

Upvotes: 2

Views: 4697

Answers (1)

Vroomfondel
Vroomfondel

Reputation: 2898

It seems it was late and you ran out of coffee when copying the command line to make ;) The only thing that was fishy in your first example was a superfluous ' right before {}. All other things run unchanged in make. In a recipe the \ has no special meaning to make, that is, if make finds it in a tabulator-preceded line after a target: then it should really run verbatim to the solo command line. The only notable exception is a \ right before the line-break, i.e. something like:

target:
    echo a very long \
    line with a \+newline in it

In this case make will take the \(newline) as indication that it shall pass the current line together with next line (and all subsequent \(newline) concatenated) to the shell in one call instead of separate shell calls for each recipe line in the default case. (Note: only the tab but not the \(newline) will be deleted from the string given to the shell - you need to trick around with variables a bit if that \(newline gets in the way.) Also, all types of quoting characters '," and also the back-tick (which SO won't allow me to write in syntax font) as well as glob-characters *,? don't invoke any kind of special behaviour - they are passed to the shell as they are. So your make file could look like:

switch_old_for_new:
    find . \( -name '*.md' -o -name '*.html' \) -exec sed -i '/id:/s/$(OLD)/$(NEW)/g' {} \;

Upvotes: 2

Related Questions