考虑到每个命令都在自己的 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)
$
替换为$$
来避免脚本使用$
;
将脚本转换为单行工作\
来转义行尾set -e
开头,以匹配make的中止子命令失败的设置。您还可以使用set -e -o pipefail
确保管道命令中的错误导致脚本中止(注意:这是bashism,因此需要SHELL := /bin/bash
或类似设置)()
或{}
括起脚本,以强调多行序列的连贯性-这不是一个典型的makefile命令序列以下是受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 ;\
}
{
后面的空格非常关键,可以防止将 {set
解释为未知命令。 - Brent Bradburn{}
和 ()
进行包装的区别非常大。 在 {}
中声明变量,特别是使用 set
修改状态,可能会对您的 shell 实例造成破坏。 ()
可以防止脚本修改您的环境,这很可能是更好的选择。 例如(这将结束您的 shell 会话):{ set -e ; } ; false
。 - Brent Bradburncommand;## my comment \\
(注释在;
和\\
之间)。这种方式似乎很好用,但是 如果 您手动运行命令(通过复制和粘贴),命令历史记录将包含注释,导致无法重复使用该命令。[注意:由于在反引号内使用反斜杠,因此此注释的语法突出显示已损坏。] - Brent BradburnONESHELL指令允许编写多行配方在同一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
foo
依赖于自身,但当然,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)
find
”吗? - Eldar Abusalimovhttps://github.com/RandyMcMillan/make-docker-start
OS :=$(shell uname -s)
export OS
.ONESHELL:
docker-start:## detect whether docker is running...
@( \
while ! docker system info > /dev/null 2>&1; do\
echo 'Waiting for docker to start...';\
if [[ '$(OS)' == 'Linux' ]]; then\
systemctl restart docker.service;\
fi;\
if [[ '$(OS)' == 'Darwin' ]]; then\
open --background -a /./Applications/Docker.app/Contents/MacOS/Docker;\
fi;\
sleep 1;\
done\
)
docker-pull:docker-start## pull alpine image
docker pull alpine
find
调用。