使用 shell 的 "*" glob,但排除一个文件并且不匹配目录?

5 shell make wildcards

我有一个 makefile 规则,可以构建一个用于分发的 zip/tarbar。在配方中,它做了一些“增值”的事情,比如确保 CR/LF 是正确的,并在打包之前确保执行位是正确的。

该项目文件的自助餐,但这里的要求是:(1)中的所有文件,除了GNUmakefile需要CR/LF,(3)GNUmakefile需要LF而已,(3)中的所有文件,除了GNUmakefile需求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
Run Code Online (Sandbox Code Playgroud)

我正在使用*并试图避免明确列出自助餐中的所有文件,因为有些文件并不明显,例如 IDE 特定文件。(这*[^<somefile>*]是一个巧妙的技巧;我是从Exclude one pattern from glob match 中得到的)。

问题是我正在匹配TestDataTestVectors执行时chmod a-x,所以我将自己排除在目录之外。

我需要改进一些东西,但我不确定如何。我想使用 shell 的 "*" glob,但排除一个文件并且不匹配目录。

我应该如何进行?

zwo*_*wol 5

我将通过使用 GNU Makefilter-outwildcard函数来解决这个问题。您的任务中唯一不能用它们完成的部分是过滤掉目录;这必须通过 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
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 3

只有zshglob 可以按类型选择文件,因此,假设 GNU make,您需要类似的东西:

SHELL = zsh
.SHELLFLAGS = -o extendedglob -c

test:
        echo ^GNUmakefile(^/)
Run Code Online (Sandbox Code Playgroud)

^GNUmakefile(带有extendedglob)适用于除GNUmakefile. (^/)是一个glob 限定符,用于选择除目录之外的任何类型的文件。另请参阅常规(.)类型的文件(不包括目录和所有其他非常规类型的文件,如 fifos、符号链接、套接字...),这看起来更像您正在寻找的内容。添加glob 限定符 ( ) 以包含隐藏 ( ot ) 文件,例如.D^GNUmakefile(.D)D.gitignore

请注意,扩展为以、、、、 、、、、、、或*[^GNUmakefile*]以外的字符结尾的非隐藏文件名列表。所以它确实会排除(因为它以 结尾),但也会排除or或。GNUmakefil*GNUmakefileefoo.afile.htmlbar.exe

要在不更改 shell 的情况下执行相同的操作,您需要诉诸类似的循环(此处相当于^GNUmakefile(.)):

test:
        set -- *; \
        for i do \
          [ -f "$$i" ] && \
            [ ! -L "$$i" ] && \
            [ "$$i" != GNUmakefile ] && \
            set -- "$$@" "$$i"; \
          shift; \
        done; \
        [ "$$#" -gt 0 ] && echo "$$@"
Run Code Online (Sandbox Code Playgroud)

(替换set -- *set -- .* *以包含隐藏文件)。

find如果您不能保证以下内容的可用性,最好可能会求助于shell glob zsh

test:
        find . ! -name . -prune ! -name '.*' ! -name GNUmakefile \
          -type f -exec echo {} +
        find TestData/. ! -name . -prune -name '*.dat' ! -name '.*' \
          -type f -exec echo {} +
Run Code Online (Sandbox Code Playgroud)

(删除! -name '.*'以包含隐藏文件)。