在 Makefile 中使用 rm -i !(*.c|Makefile)?
Using rm -i !(*.c|Makefile) in Makefile?
我有一个目录,其中有一些 C 程序文件和一个包含这些 C 文件的可执行文件的 Makefile。我可以简单地 运行 这一次删除 rm !(*.c|Makefile)
.
中的所有可执行文件
但是当我将其添加到我的 makefile 时
CFLAGS= -Wall -g -lm
SHELL=/bin/bash
careful:
echo "nothing"
clean:
rm -i !(*.c|Makefile)
我在执行命令时遇到此错误
/bin/bash: -c: line 1: syntax error near unexpected token `('
/bin/bash: -c: line 1: `rm -i !(*.c|Makefile)'
make: *** [Makefile:8: clean] Error 2
我不太了解 Bash 语法,但我知道 ()
被视为子 shell,我认为这就是我不能 运行 rm (*.c)
的原因直接在终端中,因为 *.c
不是命令(或任何有效语法)。但是 运行ning rm -i !(*.c)
在终端中工作。所以我猜 !()
在 Bash.
中被区别对待
我对这一切的假设: 在 Makefile 中,当我 运行ning make clean
它正在以不同的方式对待 !(*.c|Makefile)比在普通终端,或者不知何故它无视 !(*.c|Makefile)
中的 !
所以我的问题是:
!()
和 ()
在 Bash 中是否受到不同对待?
- 为什么
!(wildcard)
在终端中工作但在我的 Makefile
中不工作
- 如何让它在
Makefile
中工作?
Bash-specific 扩展通配模式不是开箱即用的非交互式 shells。
!(...)
纯粹是这个通配符语法的一部分,与 subshells 无关。
无论如何,更好的解决方案可能是重构它,这样您就不会依赖 Bash。
.PHONY: clean
clean:
rm -i $(filter-out $(wildcard *.c) Makefile,$(wildcard *))
Bash 参考手册没有很好地锚定 link,但是 extglob
可用的扩展通配符语法在 Pattern Matching
如果您真的想要,您也可以在 Makefile
中 shopt -s extglob
,但这变得相当复杂,因为您必须对解析器隐藏语句,直到 shell 被配置为理解这种语法。例如,
.PHONY: clean
clean:
shopt -s extglob; \
eval 'rm -i !(*.c|Makefile)'
还要注意 shopt
和 eval
如何需要在同一逻辑行上,因为开箱即用的 make
在单独的新 [=37= 中执行每个配方行] 实例(尽管您可以使用 .ONESHELL
更改它)
我有一个目录,其中有一些 C 程序文件和一个包含这些 C 文件的可执行文件的 Makefile。我可以简单地 运行 这一次删除 rm !(*.c|Makefile)
.
但是当我将其添加到我的 makefile 时
CFLAGS= -Wall -g -lm
SHELL=/bin/bash
careful:
echo "nothing"
clean:
rm -i !(*.c|Makefile)
我在执行命令时遇到此错误
/bin/bash: -c: line 1: syntax error near unexpected token `('
/bin/bash: -c: line 1: `rm -i !(*.c|Makefile)'
make: *** [Makefile:8: clean] Error 2
我不太了解 Bash 语法,但我知道 ()
被视为子 shell,我认为这就是我不能 运行 rm (*.c)
的原因直接在终端中,因为 *.c
不是命令(或任何有效语法)。但是 运行ning rm -i !(*.c)
在终端中工作。所以我猜 !()
在 Bash.
我对这一切的假设: 在 Makefile 中,当我 运行ning make clean
它正在以不同的方式对待 !(*.c|Makefile)比在普通终端,或者不知何故它无视 !(*.c|Makefile)
!
所以我的问题是:
!()
和()
在 Bash 中是否受到不同对待?- 为什么
!(wildcard)
在终端中工作但在我的Makefile
中不工作
- 如何让它在
Makefile
中工作?
Bash-specific 扩展通配模式不是开箱即用的非交互式 shells。
!(...)
纯粹是这个通配符语法的一部分,与 subshells 无关。
无论如何,更好的解决方案可能是重构它,这样您就不会依赖 Bash。
.PHONY: clean
clean:
rm -i $(filter-out $(wildcard *.c) Makefile,$(wildcard *))
Bash 参考手册没有很好地锚定 link,但是 extglob
可用的扩展通配符语法在 Pattern Matching
如果您真的想要,您也可以在 Makefile
中 shopt -s extglob
,但这变得相当复杂,因为您必须对解析器隐藏语句,直到 shell 被配置为理解这种语法。例如,
.PHONY: clean
clean:
shopt -s extglob; \
eval 'rm -i !(*.c|Makefile)'
还要注意 shopt
和 eval
如何需要在同一逻辑行上,因为开箱即用的 make
在单独的新 [=37= 中执行每个配方行] 实例(尽管您可以使用 .ONESHELL
更改它)