如何在Makefile(POSIX)中使用的sed命令中保持换行符完整?

Lon*_*ner 5 posix newline makefile escaping sed

注意:这不是“ 是否可以在Makefile中创建多行字符串变量”和其他类似问题的副本。这个问题要求不依赖纯Bash或仅GNU Make的功能的POSIX兼容解决方案。关于堆栈溢出的另一个问题没有此要求。

sed在macOS High Sierra上使用BSD获取以下shell脚本:

printf 'foo\nbaz\n' | sed '/foo/a\
bar
'
Run Code Online (Sandbox Code Playgroud)

输出为:

foo
bar
baz
Run Code Online (Sandbox Code Playgroud)

我怎样才能把同样的东西放进去Makefile?这是我尝试过的方法,但似乎不起作用:

all:
    printf 'foo\nbaz\n' | sed '/foo/a\\
    bar\
    '
Run Code Online (Sandbox Code Playgroud)

这会导致错误:

$ 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
Run Code Online (Sandbox Code Playgroud)

我如何才能sed在Makefile中正确编写上述调用,以便在make执行all目标时将尾部斜杠和换行符正确地输入到shell中?

注意:我希望Makefile兼容POSIX,并且仅使用http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html中的功能。

Sus*_*Pal 5

带有后缀的参数扩展 sed

这是一个将变量<newline>x(即换行符后跟字符x)放入变量,然后在sed命令中使用此变量的解决方案。在使用此变量时,我们使用shell参数扩展来除去x后缀,以便仅留下换行符。

all:
    NX=$$(printf '\nx'); printf 'foo\nbaz\n' | sed "/foo/a\\$${NX%x}bar$${NX%x}"
Run Code Online (Sandbox Code Playgroud)

的值NX<newline>x,因此${NX%x}评估为<newline>。这是输出:

$ make
NX=$(printf '\nx'); printf 'foo\nbaz\n' | sed "/foo/a\\${NX%x}bar${NX%x}"
foo
bar
baz
Run Code Online (Sandbox Code Playgroud)

sed使用make宏简化参数扩展

我们可以使用makemacros简化先前解决方案的使用。我们将所有笨拙的部分放入宏中。然后,我们在shell命令中扩展这些宏。这是一个例子:

NX = NX=$$(printf '\nx')
NL = $${NX%x}

all:
    $(NX); printf 'foo\nbaz\n' | sed "/foo/a\\$(NL)bar$(NL)"
Run Code Online (Sandbox Code Playgroud)

这是输出:

$ make
NX=$(printf '\nx'); printf 'foo\nbaz\n' | sed "/foo/a\\${NX%x}bar${NX%x}"
foo
bar
baz
Run Code Online (Sandbox Code Playgroud)

带有后缀的参数扩展 sed

这是类似线路上的另一种可能的解决方案。代替书写的unwiedly语法${NX%x}内的sed命令两次,它通过分配简化${NX%x}本身到另一个名为shell变量NL${NL}来代替在sed命令。

all:
    NX=$$(printf '\nx'); NL=$${NX%x}; printf 'foo\nbaz\n' | sed "/foo/a\\$${NL}bar$${NL}"
Run Code Online (Sandbox Code Playgroud)

这是输出:

$ make
NX=$(printf '\nx'); NL=${NX%x}; printf 'foo\nbaz\n' | sed "/foo/a\\${NL}bar${NL}"
foo
bar
baz
Run Code Online (Sandbox Code Playgroud)

简化参数扩展之前sedmake

可以通过make以下宏进一步简化上述解决方案的使用:

NX = NX=$$(printf '\nx'); NL=$${NX%x}
NL = $${NL}

all:
     $(NX); printf 'foo\nbaz\n' | sed "/foo/a\\$(NL)bar$(NL)"
Run Code Online (Sandbox Code Playgroud)

这是输出:

$ make
NX=$(printf '\nx'); NL=${NX%x}; printf 'foo\nbaz\n' | sed "/foo/a\\${NL}bar${NL}"
foo
bar
baz
Run Code Online (Sandbox Code Playgroud)