我想使用循环查找一些文件并将它们重命名:
for i in `find $@ -name *_cu.*`;do mv $i "$(echo $i|sed s/_cu//)"
done
这个命令在终端中可以正常工作。但是我该如何在makefile规则中执行它呢?
将非平凡的 shell 片段放入 makefile 的配方中时,有两个主要的事情需要知道:
配方中的命令(当然!)是逐一执行的,其中 command 意味着“在配方中以制表符为前缀的行”,可能会在多个 makefile 行上使用反斜杠分隔。
因此,您的 shell 片段必须写在一个(可能带有反斜杠)行上。而且它被有效地呈现给 shell 作为单行(反斜杠换行不是普通的换行符,因此不能被 shell 用作命令终止符),因此必须作为语法正确的单行。
shell 变量和 make 变量都由美元符号($@
、$i
)引入,因此您需要通过将其编写为 $$i
来将 shell 变量隐藏在 make 中。(更精确地说,任何您希望 shell 看到的美元符号都必须被从 make 中转义,方法是将其编写为 $$
。)
在 shell 脚本中通常会将不同的命令写在不同的行上,但在这里您实际上只能得到一行命令,因此必须使用分号分隔各个单独的 shell 命令。将所有这些组合应用于您的示例,将产生以下结果:
foo: bar
for i in `find $@ -name *_cu.*`; do mv $$i "$$(echo $$i|sed s/_cu//)"; done
或者等价地说:
foo: bar
for i in `find $@ -name *_cu.*`; do \
mv $$i "$$(echo $$i|sed s/_cu//)"; \
done
请注意,即使后面的代码在几行上排列得很清晰,也需要谨慎地使用分号才能让shell正常运行。
$@
?在 Makefile 中它不是有特殊的含义吗?在 shell 中,它会扩展成脚本参数列表... - fgesystem()
一样,因此没有shell脚本参数,shell的$@
始终为空。另一方面,make的$@
是指规则的目标(这里是_foo_),我假设这就是预期的意图。 - John Marshall我发现这个非常有用,尝试使用for循环来构建多个文件:
PROGRAMS = foo bar other
.PHONY all
all: $(PROGRAMS)
$(PROGRAMS):
gcc -o $@ $@.c
我花了很多时间,最终让它工作了。我在makefile中使用全局变量有一个简单的解决方案,适用于所有目标,但我不想这样做,所以我是这样做的。
target:
$(eval test_cont=$(shell sh -c "docker ps | grep test" | awk '{print $$1}'))
for container in $(test_cont);do \
docker cp ssh/id_rsa.pub $${container}:/root/.ssh/authorized_keys; \
docker exec -it $${container} chown root.root /root/.ssh/authorized_keys; \
done
'*_cu.*'
是个好主意,因为你想让find展开它,而不是调用find的shell展开它。 - John Marshall$@
不会正常工作。 - reinierpost