如何在GNU makefile中将文件分割成单独的行

问题描述:

我有一个变量,其中包含以字符串_NEWLINE_分隔的文件列表。我需要将该变量输出到一个文件中,以便每个文件位于不同的行中。诀窍是它需要在FreeBSD和Solaris上工作。如何在GNU makefile中将文件分割成单独的行

这是我现在想:

echo "lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf" | sed 's|_NEWLINE_|\'$'\n|g' 

这个工程在FreeBSD和Solaris上壳。但在GNUmakefile运行在Solaris上我得到这个(在每一行结束通知$):

lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf$ 
lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src$ 
lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf$ 

如果我从SED删除\'$'然后它工作在Solaris上,但没有在FreeBSD。也许有一种方法告诉哪个版本的使用取决于哪个系统的makefile被执行?

编辑: 感谢我创建了一个提供所需的结果,似乎是工作在两个FreeBSD和Solaris上示范的makefile bobbogo提出解决方案:

one-line := lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/\ 
priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/comm\ 
unity.conf: lib/alarms/priv/snmp_conf/community.conf 

many-lines := { echo '$(subst _NEWLINE_,' && echo ',${one-line})'; } 

.PHONY: all 
all: 
    $(shell $(many-lines) > test.txt) 
+0

在阅读接受的答案后,在我看来,上面最初的'sed'方法是一种更简单的方法(参见@ Beta的答案)。尽管使用perl。 perl是其中最具可移植性的语言之一,它总是胜过grep/sed/awk et。人。 'echo'$ {one-line}'| perl -lpe的/ _NEWLINE _/\ n/g''也许。 (或者perl -lpe BEGIN {$$/=“_NEWLINE_”}“-timtowtdi,就像Perl的人说的那样)。 – bobbogo

如果这是GNU做,然后做这一切在化妆。

one-line := lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf 

define \n 


endef 

many-lines := $(subst _NEWLINE_,${\n},${one-line}) 

现在${many-lines}正是你想要的。令人烦恼的是,在壳线上使用相当困难。如果你这样做:

tgt: 
    echo '${many-lines}' 

作将调用单独外壳为每个线。第一次shell调用将得到一个未配对的',并退出时出现错误。

.ONESHELL: 
tgt: 
    echo '${many-lines}' 

将以侵入式的方式工作。正确的解决方法是确保${many-lines}的每一行都有有效的sh语法。一些类似于:

echolines = $(subst ${\n},'${\n}echo ',echo '${many-lines}') 
.PHONY: aa 
aa: 
    $(call echolines,${many-lines}) 

呃。

+0

谢谢,这是一个好的开始。我正在考虑类似的事情,但没有耐心弄清楚在哪里摆放回声。你能够在文件中添加每一行的回显,因为这是最终的目标吗?我认为在你的方法中,每行应该有这样的格式:“echo'target:file'>> test.txt”但是我不知道在哪里添加“>> test.txt”部分。对我来说,最后一行看起来会有问题,因为它不以“\ n”结尾,不能轻易替换。我的意思是,在最后添加_NEWLINE_应该仍然可以,但是会变得更加混乱。 – Amiramix

+0

其实,我认为我得到'$ echolines'错误,因为echo总是添加一个换行符(除了''echo's中的'-c'外)。睡过之后,更好的方法是将'str1 \ nstr2 \ nstr3 \ n'变成'{echo'str1'&& echo'str2'&& echo'str3'}''。这是一个单独的shell调用,并且对于单一的间接寻址('$(call echolines2,$ {many-lines})> $ @')会很满意。 – bobbogo

+0

我不确定我可能做错了什么,但仍然不起作用:'many-lines:= echo'$(subst _NEWLINE_,'&& echo',$ {one-line})'''echolines = $ (subst $ {\ n},'$ {\ n} echo',$ {many-lines})''$(call echolines,$ {many-lines})> test.txt'在文件中打印一行,另外两个到标准输出。 – Amiramix

免责声明:我有没有使用Solaris或FreeBSD的经验...无论如何。

在make中,您可以使用$(patsubst pattern,replacement,text)来替换一个模式。 试试这个...

FILENAMES := "lib/alarms-1.2/priv/snmp_conf/agent.conf: lib/alarms/priv/snmp_conf/agent.conf_NEWLINE_lib/alarms-1.2/priv/snmp_conf/agent.conf.src: lib/alarms/priv/snmp_conf/agent.conf.src_NEWLINE_lib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf" 

.PHONY: all 

all: 
    @echo $(patsubst _NEWLINE_,${\n},$(FILENAMES)) 
+0

这不起作用,因为_NEWLINE_不是与其他词分开的空格。但谢谢你的尝试。 – Amiramix

+0

顺便说一句,使用subst而不是patsubst也不起作用(因为\ n没有被正确替换)。我想你没有测试你的代码? – Amiramix

尝试过许多不同的解决方案,包括本答复中提到定义\nAdd a newline in Makefile 'foreach' loop

真正的问题是实现跨平台的echo命令的不一致,而事实上,由默认make使用sh调用shell命令,它本身非常不灵活。

我发现了一个更好的感谢这样的回答方式:"echo -e" when called directly and when called via a shell-script

更好的方法是使用printf代替echo

构建字符串\n代替_NEWLINE_分离是进入单独的部分输出文件中的行:

some_string = lib/alarms-1.2/priv/snmp_conf/target_params.conf: lib/alarms/priv/snmp_conf/target_params.conf\nlib/alarms-1.2/priv/snmp_conf/community.conf: lib/alarms/priv/snmp_conf/community.conf\n 

然后在makefile中打印它只是简单的这个:

@printf "$(some_string)" >> $(some_file) 

适用于FreeBSD和Solaris。

+0

这在_some_string_包含'%'字符的情况下很脆弱。 – bobbogo

作为替代,我想你的第一种方法将工作,如果你要加倍$“逃离”是:

sed 's|_NEWLINE_|\'$$'\n|g' 
+0

不,它没有。在Solaris上它输出conf $ nlib(用$ n替换_NEWLINE_)。 – Amiramix