1

Is there a way to convince m4 to replace a macro in the middle of a word?

I would like this file, day.m4:

define(Sat,Cat)dnl
Saturday

and this command:

m4 day.m4

to produce this output:

Caturday

As shown, m4 will not do this.

Alternatively, is there a way to get sed to perform multiple substitutions simultaneously? That is, without passing over the file for each substitution.

I can pipe a bunch of sed commands together or use a combination of sed and m4 and that's not so bad but if there's a convenient way to do this with one input file and one command that'd be preferable.

Any other commonly available tool would be fine too.

My goal is to use this for creating files from templates. Most of the tokens that are to be replaced are space separated.

2 Answers 2

0

It sounds like all that you need is:

sed -e sub1 -e sub2 file

Where sub has the form:

s/sat/cat/g

You could also put all your substitutions in a file and run it with:

sed -f scriptfile filetomodify
0

Using patsubst()

m4 provides a search-and-replace function, which can perform substitutions anywhere, including mid-word, called patsubst:

Builtin: patsubst (string, regexp, [replacement])

Searches string for matches of regexp, and substitutes replacement for each match.

This doesn't involve setting up a new definition, so it can't be applied by default to all future input. Instead, you'll have to "sandwich" the full input text inside the function call:

patsubst(dnl
[...]
Saturday
[...]
,`Sat',`Cat')dnl

Using changeword()

m4 also provides changeword:

A file being processed by m4 is split into quoted strings, words (potential macro names) and simple tokens (any other single character). Initially a word is defined by the following regular expression:

[_a-zA-Z][_a-zA-Z0-9]*

Using changeword, you can change this regular expression:

Unfortunately, the changeword function is non-standard. It's only available if you requested it with --enable-changeword at compile time.

With it enabled, you could eg. force m4 to only accept three-letter words.

define(`Sat',`Cat')dnl
changeword(`[A-Za-z][a-z]?[a-z]?')dnl
Saturday

But changeword has additional problems:

regex must obey the constraint that every prefix of the desired final pattern is also accepted by the regular expression.

[...]

Tightening the lexical rules is less useful, because it will generally make some of the builtins unavailable.

The above pattern would prevent further definitions (it only even recognises dnl because that's exactly three letters). So as well as being non-standard, it's not really suited to what you're trying to do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.