以下命令集在Linux提示符下起作用。
%cd ${ADIR}/exe; shopt -s extglob; rm -rf !(BDIR)
但是在Makefile中不起作用
Linux命令-有效
%cd ${ADIR}/exe; shopt -s extglob; rm -rf !(BDIR)
Makefile中的命令
@cd ${ADIR}/exe; shopt -s extglob; rm -rf !\(BDIR\)
发送文件消息
rm: cannot remove `!(BDIR)': No such file or directory
答案 0 :(得分:1)
Makefile的问题在于它转义了(
和)
,这使得Shell可以按字面意义解释它们。
第二期,
/bin/sh: -c: line 0: syntax error near unexpected token `('
是由make
使用sh
而不是bash
执行命令引起的。
bash仅支持!(...)
通配符语法(和extglob
),而不是sh支持。
您可以明确地致电bash
:
@bash -c 'cd ${ADIR}/exe; shopt -s extglob; rm -rf !(BDIR)'
但这也不起作用,因为extglob
在读取下一行输入之前不会生效,因此!( )
仍然会引发语法错误。
我们需要一种方法,可以通过一次调用Shell来运行多行命令。不幸的是,make
使得这一过程变得不必要了。
一种可能的解决方案:
SHELL = /bin/bash
...
@bash -c $$'cd ${ADIR}/exe; shopt -s extglob\nrm -rf !(BDIR)'
这告诉make
使用bash
执行所有配方(不是/bin/sh
)。然后,我们再次手动运行bash
,但使用$'...'
引用命令字符串。这样,我们就可以编写\n
来嵌入文字换行符,从而使extglob
/ !( ... )
正常工作。
我们需要使用两个$$
来使$
的{{1}}逸出,因此make
变成$'...'
。
我对这种解决方案不是很满意。
答案 1 :(得分:1)
不幸的是,bash有一种怪异的行为,因为shopt设置要等到换行符才会生效,因此同一行上的任何混淆都不会识别出来。在您的shell提示符下尝试以下操作:
$ shopt -s extglob; echo !(BDIR)
bash: !: event not found
然后尝试两行:
$ shopt -s extglob
$ echo !(BDIR)
...works
不幸的是,这意味着几乎不可能在make上使用它。
您应该使用在Triplee注释中建议的POSIX兼容版本,并且完全避免使用特殊的Shell。
哦,看来答案已删除。无论如何,改为执行以下操作:
foo:
cd ${ADIR}/exe && for f in *; do \
case $$f in (BDIR) : ok ;; (*) rm -rf "$$f" ;; esac; \
done