Tom
Tom

Reputation: 7223

How to use sed in a Makefile

I have tried putting the following in my Makefile:

@if [ $(DEMO) -eq 0 ]; then \
    cat sys.conf | sed -e "s#^public_demo[\s=].*$#public_demo=0#" >sys.conf.temp; \
else \
    cat sys.conf | sed -e "s#^public_demo[\s=].*$#public_demo=1#" >sys.conf.temp; \
fi

but when I run make, I get the following error:

sed: -e expression #1, char 30: unterminated `s' command

If I run the exact lines that contain sed in the console, they behave correctly.

Why am I getting this error and how can the problem be fixed?

Upvotes: 30

Views: 40293

Answers (6)

rubo77
rubo77

Reputation: 20845

I tried double $$ sign but it didn't work in my problem, maybe $$$$ or $$$$$$$$ would have worked, because my Makefile calls other Makefiles and so on. But I found a better solution:

Create a shell file replacer.sh in the same folder as your Makefile that executes the sed command. Give it executable bit with

chmod +x replacer.sh

Now you can call this file in your Makefile:

./replacer.sh

Upvotes: 0

Erik Edin
Erik Edin

Reputation: 690

TL;DR: Use single quotes and use two $ signs. The expression is expanded twice, once by make and once by bash. The rest of this answer provides further context.

It might be the $ sign in the substitution that is interpreted by make as a variable. Try using two of them like .*$$#public_demo. Then make will expand that to a single $.

EDIT: This was only half the answer. As cristis answered: the other part is that one needs to use single quotes to prevent bash from expanding the $ sign too.

Upvotes: 37

jiych.guru
jiych.guru

Reputation: 664

The make version in my machine is:

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for x86_64-redhat-linux-gnu

And the sed version:

$ sed --version
GNU sed version 4.2.1

I must add backslash for $ to prevent sed taking it as end of line:

cat sys.conf | sed -e 's#^public_demo[\s=].*\$$#public_demo=0#' >sys.conf.temp

Upvotes: 3

jcomeau_ictx
jcomeau_ictx

Reputation: 38432

one problem I had with using sed in a makefile isn't addressed by the current answers, so I'll explain it here. I was populating Bash variables like so: remote_owner=$$($(MAKE) remote.owner) and then using those variables in my sed substitution. problem is, due to the convoluted way my rules are set up, remote_owner could have make's own output in it, giving me the error:

sed: -e expression #1, char 69: unknown option to `s'
make: *** [alter_table_local.sql] Error 1

for example, by adding debugging messages, I found local_owner set to:

make[1]: Entering directory `/home/jcomeau/rentacoder/jh'
jcomeau

the answer was to add the --silent option to make: remote_owner=$$($(MAKE) --silent remote.owner)

Upvotes: 0

Sjoerd
Sjoerd

Reputation: 75609

Use something else than # to separate parts.

Upvotes: 0

cristis
cristis

Reputation: 1995

I suggest you use single quotes instead of double quotes, the $ might be processed as a special char by make before running sed:

cat sys.conf | sed -e 's#^public_demo[\s=].*$#public_demo=0#' >sys.conf.temp;

Upvotes: 9

Related Questions