Note: This is not a duplicate of Is it possible to create a multi-line string variable in a Makefile and other such questions. This question requests POSIX compliant solutions that do not depend Bash-only or GNU Make-only features. The other question on Stack Overflow does not have this requirement.
Take this shell script using the BSD sed
on macOS High Sierra:
printf 'foo\nbaz\n' | sed '/foo/a\
bar
'
The output is:
foo
bar
baz
How can I put the same thing in a Makefile
? Here is what I tried but it does not seem to work:
all:
printf 'foo\nbaz\n' | sed '/foo/a\\
bar\
'
This leads to errors:
$ make
printf 'foo\nbaz\n' | sed '/foo/a\\
/bin/sh: -c: line 0: unexpected EOF while looking for matching `''
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [all] Error 2
How can I write the above sed
invocation correctly in a Makefile such that when make
executes the all
target it feeds the trailing slash and the newlines correctly to the shell?
Note: I would like the Makefile
to be POSIX compliant and use only features from http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html.
The sed command can add a new line after a pattern match is found. The "a" command to sed tells it to add a new line after a match is found. The sed command can add a new line before a pattern match is found. The "i" command to sed tells it to add a new line before a match is found.
If you want to inhibit the display of commands during a particular make run, you can use the -s option. If you want to inhibit the display of all command lines in every run, add the special target . SILENT to your makefile .
sed
Here is a solution that puts <newline>x
(i.e., newline followed by the character x
) in a variable and then uses this variable in the sed
command. While using this variable, we use shell parameter expansion to get rid of the x
suffix, so that we are only left with a newline.
all:
NX=$$(printf '\nx'); printf 'foo\nbaz\n' | sed "/foo/a\\$${NX%x}bar$${NX%x}"
The value of NX
is <newline>x
, so ${NX%x}
evaluates to just <newline>
. Here is the output:
$ make
NX=$(printf '\nx'); printf 'foo\nbaz\n' | sed "/foo/a\\${NX%x}bar${NX%x}"
foo
bar
baz
sed
with make
MacrosWe can simplify the usage of the previous solution with make
macros. We put all the unwieldy parts into macros. Then we expand those macros in the shell commands. Here is an example:
NX = NX=$$(printf '\nx')
NL = $${NX%x}
all:
$(NX); printf 'foo\nbaz\n' | sed "/foo/a\\$(NL)bar$(NL)"
Here is the output:
$ make
NX=$(printf '\nx'); printf 'foo\nbaz\n' | sed "/foo/a\\${NX%x}bar${NX%x}"
foo
bar
baz
sed
Here is another possible solution on similar lines. Instead of writing the unwiedly syntax of ${NX%x}
within the sed
command twice, it is simplified by assigning ${NX%x}
itself to another shell variable named NL
and ${NL}
is used instead in the sed
command.
all:
NX=$$(printf '\nx'); NL=$${NX%x}; printf 'foo\nbaz\n' | sed "/foo/a\\$${NL}bar$${NL}"
Here is the output:
$ make
NX=$(printf '\nx'); NL=${NX%x}; printf 'foo\nbaz\n' | sed "/foo/a\\${NL}bar${NL}"
foo
bar
baz
sed
with make
MacrosThe usage of the above solution can be simplified further with make
macros as follows:
NX = NX=$$(printf '\nx'); NL=$${NX%x}
NL = $${NL}
all:
$(NX); printf 'foo\nbaz\n' | sed "/foo/a\\$(NL)bar$(NL)"
Here is the output:
$ make
NX=$(printf '\nx'); NL=${NX%x}; printf 'foo\nbaz\n' | sed "/foo/a\\${NL}bar${NL}"
foo
bar
baz
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With