GNU中的递归通配符make?

Rog*_*mbe 83 makefile gnu-make

自从我使用以来已经有一段时间了make,所以请耐心等待......

我有一个flac包含.FLAC文件的目录.我有一个相应的目录,mp3包含MP3文件.如果FLAC文件比相应的MP3文件(或相应的MP3文件不存在)更新,那么我想运行一堆命令将FLAC文件转换为MP3文件,然后复制标签.

踢球者:我需要flac递归搜索目录,并在mp3目录中创建相应的子目录.目录和文件名称中可以包含空格,并以UTF-8命名.

而且我想make用来驱动它.

ndi*_*dim 107

我会尝试这些方法

FLAC_FILES = $(shell find flac/ -type f -name '*.flac')
MP3_FILES = $(patsubst flac/%.flac, mp3/%.mp3, $(FLAC_FILES))

.PHONY: all
all: $(MP3_FILES)

mp3/%.mp3: flac/%.flac
    @mkdir -p "$(@D)"
    @echo convert "$<" to "$@"
Run Code Online (Sandbox Code Playgroud)

make初学者的几个快速笔记:

  • @前面的命令在防止make从实际运行它之前打印命令.
  • $(@D)是目标文件名的目录部分($@)
  • 确保包含shell命令的行以制表符开头,而不是空格.

即使这应该处理所有UTF-8字符和东西,它将在文件或目录名称中的空格处失败,因为make使用空格来分隔makefile中的东西,我不知道如何解决这个问题.所以这让你只有一个shell脚本,我担心: - /

  • 当目录名称中包含空格时,似乎不起作用。 (2认同)

lar*_*lte 45

您可以像这样定义自己的递归通配符函数:

rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
Run Code Online (Sandbox Code Playgroud)

第一个参数($1)是目录名称,第二个($2)是您要匹配的模式.

例子

要查找当前目录中的所有C文件:

$(call rwildcard,.,*.c)
Run Code Online (Sandbox Code Playgroud)

要查找所有.c.h文件src:

$(call rwildcard,src,*.c *.h)
Run Code Online (Sandbox Code Playgroud)

资源

  • 我正在使用GNU Make 3.81,它似乎对我有用.但是,如果任何文件名中包含空格,它将无法工作.请注意,它返回的文件名具有相对于当前目录的路径,即使您只列出子目录中的文件也是如此. (3认同)
  • 这确实是一个例子,“ make”是图灵焦油坑(请参见此处:http://yosefk.com/blog/fun-at-the-turing-tar-pit.html)。它甚至没有那么难,但是必须阅读以下内容:https://www.gnu.org/software/make/manual/html_node/Call-Function.html,然后“了解重复发生”。您必须逐字地递归编写;这不是“自动包括子目录中的内容”的日常理解。这是实际的递归。但是请记住-“要了解复发,就必须了解复发”。 (2认同)

ken*_*orb 6

如果您使用的是 Bash 4.x,则可以使用新的 globbing 选项,例如:

SHELL:=/bin/bash -O globstar
list:
  @echo Flac: $(shell ls flac/**/*.flac)
  @echo MP3: $(shell ls mp3/**/*.mp3)
Run Code Online (Sandbox Code Playgroud)

这种递归通配符可以找到您感兴趣的所有文件(.flac.mp3或其他文件)。氧

  • 对我来说,即使只是 $(wildcard flac/**/*.flac) 似乎也有效。OS X、Gnu Make 3.81 (3认同)
  • 我尝试了 $(wildcard ./**/*.py) ,它的行为与 $(wildcard ./*/*.py) 相同。我不认为 make 实际上支持 **,并且当您相邻使用两个 * 时它不会失败。 (2认同)