如何删除Makefile中除目录以外的所有目录?

时间:2019-06-08 06:57:28

标签: bash shell makefile sh

以下命令集在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

2 个答案:

答案 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