如何在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)
如果这是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})
呃。
谢谢,这是一个好的开始。我正在考虑类似的事情,但没有耐心弄清楚在哪里摆放回声。你能够在文件中添加每一行的回显,因为这是最终的目标吗?我认为在你的方法中,每行应该有这样的格式:“echo'target:file'>> test.txt”但是我不知道在哪里添加“>> test.txt”部分。对我来说,最后一行看起来会有问题,因为它不以“\ n”结尾,不能轻易替换。我的意思是,在最后添加_NEWLINE_应该仍然可以,但是会变得更加混乱。 – Amiramix
其实,我认为我得到'$ echolines'错误,因为echo总是添加一个换行符(除了''echo's中的'-c'外)。睡过之后,更好的方法是将'str1 \ nstr2 \ nstr3 \ n'变成'{echo'str1'&& echo'str2'&& echo'str3'}''。这是一个单独的shell调用,并且对于单一的间接寻址('$(call echolines2,$ {many-lines})> $ @')会很满意。 – bobbogo
我不确定我可能做错了什么,但仍然不起作用:'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))
尝试过许多不同的解决方案,包括本答复中提到定义\n
:Add 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。
这在_some_string_包含'%'字符的情况下很脆弱。 – bobbogo
作为替代,我想你的第一种方法将工作,如果你要加倍$
“逃离”是:
sed 's|_NEWLINE_|\'$$'\n|g'
不,它没有。在Solaris上它输出conf $ nlib(用$ n替换_NEWLINE_)。 – Amiramix
在阅读接受的答案后,在我看来,上面最初的'sed'方法是一种更简单的方法(参见@ Beta的答案)。尽管使用perl。 perl是其中最具可移植性的语言之一,它总是胜过grep/sed/awk et。人。 'echo'$ {one-line}'| perl -lpe的/ _NEWLINE _/\ n/g''也许。 (或者perl -lpe BEGIN {$$/=“_NEWLINE_”}“-timtowtdi,就像Perl的人说的那样)。 – bobbogo