我有一个 makefile 规则,可以构建用于分发的 zip/tarbar。在配方中,它做了一些“增值”的事情,例如确保 CR/LF 正确,并确保打包前执行位正确。
该项目有大量文件,但要求如下:(1) 除GNUmakefile
need之外的所有文件CR/LF
,(3)仅GNUmakefile
need LF
,(3) 除GNUmakefile
need之外的所有文件a-x
。
菜谱是这样的:
.PHONY: convert
convert:
chmod a-x *[^GNUmakefile*] TestData/*.dat TestVectors/*.txt
unix2dos --keepdate --quiet *[^GNUmakefile*] TestData/*.dat TestVectors/*.txt
dos2unix --keepdate --quiet GNUmakefile
我正在使用*
并试图避免明确列出自助餐中的所有文件,因为有些文件并不明显,例如 IDE 特定文件。 (*[^<somefile>*]
这是一个巧妙的技巧;我从从全局匹配中排除一种模式)。
问题是我正在匹配TestData
和TestVectors
时执行chmod a-x
,所以我将自己排除在目录之外。
我需要改进一些东西,但我不知道如何改进。我想使用 shell 的“*” glob,但排除一个文件并且不匹配目录。
我应该如何进行?
答案1
我将通过使用 GNU Makefilter-out
和wildcard
函数来解决这个问题。您的任务中唯一不能用它们完成的部分是过滤掉目录;这必须通过 shell 来完成。下面的代码未经测试,并假设 (a) 任何文件名中没有空格或 shell 元字符,(b)TestData/*.dat
并且TestVectors/*.txt
不需要检查目录。
NORM_TOPLEVEL := $(shell for f in $(filter-out GNUMakefile,$(wildcard *)); \
do [ -d "$$f" ] || printf '%s\n' "$$f"; done)
NORM_TESTDIRS := $(wildcard TestData/*.dat) $(wildcard TestVectors/*.txt)
convert:
chmod a-x $(NORM_TOPLEVEL) $(NORM_TESTDIRS)
unix2dos --keepdate --quiet $(NORM_TOPLEVEL) $(NORM_TESTDIRS)
dos2unix --keepdate --quiet GNUmakefile
.PHONY: convert
答案2
只有zsh
glob 可以按类型选择文件,因此,假设 GNU make
,您需要类似的东西:
SHELL = zsh
.SHELLFLAGS = -o extendedglob -c
test:
echo ^GNUmakefile(^/)
^GNUmakefile
(带有extendedglob
)适用于除GNUmakefile
.(^/)
是一个全局限定符选择目录以外的任何类型的文件。另请(.)
参阅文件类型常规的(不包括目录和所有其他非常规类型的文件,例如 fifo、符号链接、套接字...)这看起来更像您正在寻找的内容。添加D
glob 限定符 ( ^GNUmakefile(.D)
) 以包含隐藏 ( Dot ) 文件,例如.gitignore
.
请注意,扩展为以、、、、、、 、、、、或*[^GNUmakefile*]
以外的字符结尾的非隐藏文件名列表。所以它确实会排除(因为它以 结尾),但也会排除or或。G
N
U
m
a
k
e
f
i
l
*
GNUmakefile
e
foo.a
file.html
bar.exe
要在不更改 shell 的情况下执行相同的操作,您需要诉诸类似的循环(此处相当于^GNUmakefile(.)
):
test:
set -- *; \
for i do \
[ -f "$$i" ] && \
[ ! -L "$$i" ] && \
[ "$$i" != GNUmakefile ] && \
set -- "$$@" "$$i"; \
shift; \
done; \
[ "$$#" -gt 0 ] && echo "$$@"
(替换set -- *
为set -- .* *
以包含隐藏文件)。
find
如果您不能保证以下内容的可用性,zsh
最好可能会求助于shell glob:
test:
find . ! -name . -prune ! -name '.*' ! -name GNUmakefile \
-type f -exec echo {} +
find TestData/. ! -name . -prune -name '*.dat' ! -name '.*' \
-type f -exec echo {} +
(删除! -name '.*'
以包含隐藏文件)。
答案3
如果您希望过滤更高级的条件,使用 Python 可以轻松扩展表达式。几乎所有地方都安装了Python。这有点冗长,但它确实有效。
示例生成文件:
all:
chmod a-x $(shell python -c "import glob; import os.path; print(' '.join([x for x in glob.glob('TestData/*.dat') + glob.glob('TestVectors/*.txt') if not (os.path.isdir(x) or x == 'GNUmakefile')]))")