如何从目标的外部shell调用设置Makefile变量

如何从目标的外部shell调用设置Makefile变量,shell,makefile,Shell,Makefile,我需要逐行从某个文本文件中读取文件列表,然后将其转换为-a filename1-a filename2-a filename3的顺序。 我尝试过这样做,但在这种情况下,setting FILES变量的语法似乎是错误的: files_pack: @while read -r file; do \ FILES += "-a $$file"; \ done <$(LIST_FILE) some_util $(FILES) 文件包: @读取-r文件时;做

我需要逐行从某个文本文件中读取文件列表,然后将其转换为
-a filename1-a filename2-a filename3
的顺序。 我尝试过这样做,但在这种情况下,setting FILES变量的语法似乎是错误的:

files_pack:
    @while read -r file; do \
         FILES += "-a $$file"; \
    done <$(LIST_FILE)
    some_util $(FILES)
文件包:
@读取-r文件时;做\
FILES+=“-a$$文件”\

已完成的Shell分配在
=
/
+=
周围不能有空格

另外,
$(文件)
将通过make进行扩展。您需要
“$${FILES[@]}”
在那里

我还修改了您的代码以使用数组而不是字符串,这样名称中带有空格/等的文件可以正常工作

files_pack:
    @while read -r file; do \
         FILES+=(-a "$$file"); \
    done <$(LIST_FILE)
    some_util "$${FILES[@]}"
或全球:

SHELL := /bin/bash

Shell分配在
=
/
+=
周围不能有空格

另外,
$(文件)
将通过make进行扩展。您需要
“$${FILES[@]}”
在那里

我还修改了您的代码以使用数组而不是字符串,这样名称中带有空格/等的文件可以正常工作

files_pack:
    @while read -r file; do \
         FILES+=(-a "$$file"); \
    done <$(LIST_FILE)
    some_util "$${FILES[@]}"
或全球:

SHELL := /bin/bash

如果列表文件每行有一个文件,您需要做的就是在每行前面加上
-a
,那么您需要的是

files_pack:
       some_util $$(sed 's/^/-a /' $(LIST_FILE))

如果列表文件每行有一个文件,您需要做的就是在每行前面加上
-a
,那么您需要的是

files_pack:
       some_util $$(sed 's/^/-a /' $(LIST_FILE))
这也有效:

FILES=$(shell cat${LIST\u文件)
FILES_OPT=$(addprefix-a,${FILES})

此解决方案不依赖于bash,适用于所有通用shell,并且不需要安装“sed”。

此解决方案也适用于:

FILES=$(shell cat${LIST\u文件)
FILES_OPT=$(addprefix-a,${FILES})

此解决方案不依赖于bash,适用于所有通用shell,并且不需要安装“sed”。

受此启发,一个简单的解决方案可用于任何shell,但如果文件名包含空格或元字符,则会失败:

files_pack:
    some_util $(shell printf " -a %s" $$(cat $(FILES)))
这可以改进为处理带有空格或撇号以外的特殊字符的文件名:

files_pack:
    some_util $(shell IFS="$$(printf '\n+')"; IFS="$${IFS%+}"; printf " -a '%s'" $$(cat $(FILES)))
IFS
设置为换行符+然后删除+的特殊顺序,是我所知道的唯一一种Posix兼容的方式,可以将
IFS
设置为一个不涉及带物理换行符的命令行的换行符。(简单的命令替换会删除后续换行符,而不管
IFS
的设置如何)

使用bash,可以使用
%q
printf格式(以及一些其他bash简化格式)简化并使其更加健壮:

文件\u pack:SHELL:=/bin/bash
一些_util$(shell IFS=$$'\n';printf“-a%q”$$(的灵感来源于一个简单的解决方案,该解决方案可用于任何shell,但如果文件名包含空格或元字符,则会失败:

files_pack:
    some_util $(shell printf " -a %s" $$(cat $(FILES)))
这可以改进为处理带有空格或撇号以外的特殊字符的文件名:

files_pack:
    some_util $(shell IFS="$$(printf '\n+')"; IFS="$${IFS%+}"; printf " -a '%s'" $$(cat $(FILES)))
IFS
设置为换行符+然后删除+的特殊顺序,是我所知道的唯一一种Posix兼容的方式,可以将
IFS
设置为一个不涉及带物理换行符的命令行的换行符。(简单的命令替换会删除后续换行符,而不管
IFS
的设置如何)

使用bash,可以使用
%q
printf格式(以及一些其他bash简化格式)简化并使其更加健壮:

文件\u pack:SHELL:=/bin/bash

一些_util$(shell IFS=$$'\n';printf“-a%q”$$(
FILES+=
是否为有效的shell语法?@Jens True。这需要makefile中的
shell=/bin/bash
才能保证工作。
+=
添加到
bash
3.1中。
FILES+=
是否为有效的shell语法?@Jens True。这需要makefile中的
shell=/bin/bash
才能保证工作。
是在
bash
3.1中添加的。在行内容中添加单引号可能也是个好主意(如果名称中有空格)但这实际上并不安全,因为它们也可能包含单引号,这将结束参数并重新引入空格/任意命令执行等问题。在行内容中添加单引号可能也是一个好主意(如果名称中有空格)但这实际上并不安全,因为它们也可能包含单引号,这将结束参数并重新引入空格/任意命令执行等问题。它也不能/不能处理带有空格的文件名。它也不能/不能处理带有空格的文件名。我想知道,是否也可以处理不同的文件结尾ings-
/r/n
和列表文件中的
/n
?@AntonKochkov:当然,您只需将
\r
添加到
IFS
(当然,这也会将
\r
本身识别为行尾,但通常这不是问题。)我想知道,是否也可以处理不同的文件结尾-
/r/n
和列表文件中的
/n