考虑到每个命令都在自己的 shell 中运行,那么在 makefile 中运行多行 bash 命令的最佳方法是什么?例如,像这样:
for i in `find`
do
all="$all $i"
done
gcc $all
您可以使用反斜杠来续行。但是请注意,shell 接收连接成一行的整个命令,因此您还需要用分号终止某些行:
foo:
for i in `find`; \
do \
all="$$all $$i"; \
done; \
gcc $$all
但是,如果您只想获取find
调用返回的整个列表并将其传递给gcc
,则实际上不一定需要多行命令:
foo:
gcc `find`
或者,使用更传统的 shell$(command)
方法(注意$
转义):
foo:
gcc $$(find)
As indicated in the question, every sub-command is run in its own shell. This makes writing non-trivial shell scripts a little bit messy -- but it is possible! The solution is to consolidate your script into what make will consider a single sub-command (a single line).
$
by replacing with $$
;
between commands\
set -e
to match make's provision to abort on sub-command failure()
or {}
to emphasize the cohesiveness of a multiple line sequence -- that this is not a typical makefile command sequenceHere's an example inspired by the OP:
mytarget:
{ \
set -e ;\
msg="header:" ;\
for i in $$(seq 1 3) ; do msg="$$msg pre_$${i}_post" ; done ;\
msg="$$msg :footer" ;\
echo msg=$$msg ;\
}
ONESHELL 指令允许编写多行配方以在同一个 shell 调用中执行。
all: foo
SOURCE_FILES = $(shell find . -name '*.c')
.ONESHELL:
foo: ${SOURCE_FILES}
FILES=()
for F in $^; do
FILES+=($${F})
done
gcc "$${FILES[@]}" -o $@
但是有一个缺点:特殊前缀字符('@'、'-' 和 '+')的解释不同。
https://www.gnu.org/software/make/manual/html_node/One-Shell.html
当然,编写 Makefile 的正确方法是实际记录哪些目标取决于哪些源。在平凡的情况下,建议的解决方案将foo
依赖于自身,但当然,make
它足够聪明,可以放弃循环依赖。但是如果你在你的目录中添加一个临时文件,它会“神奇地”成为依赖链的一部分。最好一劳永逸地创建一个明确的依赖关系列表,也许通过脚本。
GNU make 知道如何运行以从一组文件中gcc
生成可执行文件,所以也许你真正需要的只是.c
.h
foo: $(wildcard *.h) $(wildcard *.c)
仅调用命令有什么问题?
foo:
echo line1
echo line2
....
而对于你的第二个问题,你需要$
通过使用来逃避$$
,即bash -c '... echo $$a ...'
。
编辑:您的示例可以重写为单行脚本,如下所示:
gcc $(for i in `find`; do echo $i; done)