GNU make 中的递归通配符?
我已经有一段时间没有使用 make
了,所以请耐心等待...
我有一个目录 flac
,其中包含 .FLAC 文件。我有一个相应的目录,mp3
,其中包含 MP3 文件。如果 FLAC 文件比相应的 MP3 文件更新(或者相应的 MP3 文件不存在),那么我想运行一堆命令将 FLAC 文件转换为 MP3 文件,并复制标签。
更关键的是:我需要递归搜索 flac
目录,并在 mp3
目录中创建相应的子目录。目录和文件的名称中可以包含空格,并以 UTF-8 命名。
我想使用 make
来驱动它。
It's been a while since I've used make
, so bear with me...
I've got a directory, flac
, containing .FLAC files. I've got a corresponding directory, mp3
containing MP3 files. If a FLAC file is newer than the corresponding MP3 file (or the corresponding MP3 file doesn't exist), then I want to run a bunch of commands to convert the FLAC file to an MP3 file, and copy the tags across.
The kicker: I need to search the flac
directory recursively, and create corresponding subdirectories in the mp3
directory. The directories and files can have spaces in the names, and are named in UTF-8.
And I want to use make
to drive this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我会尝试一些
针对
make
初学者的快速说明:@
会阻止make
打印命令在实际运行之前。$(@D)
是目标文件名的目录部分 ($@
)即使这应该处理所有 UTF-8 字符和内容,它也会在文件或目录名中的空格处失败,因为
make
使用空格来分隔 makefile 中的内容,并且我不知道有什么方法可以解决这个问题。恐怕只剩下一个 shell 脚本了:-/I would try something along these lines
A couple of quick notes for
make
beginners:@
in front of the commands preventsmake
from printing the command before actually running it.$(@D)
is the directory part of the target file name ($@
)Even if this should handle all UTF-8 characters and stuff, it will fail at spaces in file or directory names, as
make
uses spaces to separate stuff in the makefiles and I am not aware of a way to work around that. So that leaves you with just a shell script, I am afraid :-/您可以像这样定义自己的递归通配符函数:
第一个参数(
$1
)是目录列表,第二个参数($2
)是您想要的模式列表匹配。示例:
查找当前目录中的所有 C 文件:
查找
src
中的所有.c
和.h
文件:该函数是基于本文的实现,一些改进。
You can define your own recursive wildcard function like this:
The first parameter (
$1
) is a list of directories, and the second ($2
) is a list of patterns you want to match.Examples:
To find all the C files in the current directory:
To find all the
.c
and.h
files insrc
:This function is based on the implementation from this article, with a few improvements.
如果您使用的是 Bash 4.x,则可以使用新的 globbing 选项,例如:
这种递归通配符可以找到您感兴趣的所有文件(.flac、.mp3 或其他文件)。氧
If you're using Bash 4.x, you can use a new globbing option, for example:
This kind of recursive wildcard can find all the files of your interest (.flac, .mp3 or whatever). O
FWIW,我在 Makefile 中使用了类似的内容:
上面的示例将从当前目录('.')中搜索所有“纯文件”( >'-type f') 并将
RECURSIVE_MANIFEST
make 变量设置为其找到的每个文件。然后,您可以使用模式替换来减少此列表,或者向 find 提供更多参数以缩小其返回的范围。请参阅find 的手册页。FWIW, I've used something like this in a Makefile:
The example above will search from the current directory ('.') for all "plain files" ('-type f') and set the
RECURSIVE_MANIFEST
make variable to every file it finds. You can then use pattern substitutions to reduce this list, or alternatively, supply more arguments into find to narrow what it returns. See the man page for find.我的解决方案基于上面的解决方案,使用 sed 而不是 patsubst 来破坏 find 的输出并转义空格。
从 flac/ 到 ogg/
警告:
My solution is based on the one above, uses
sed
instead ofpatsubst
to mangle the output offind
AND escape the spaces.Going from flac/ to ogg/
Caveats:
这是我快速编写的一个 Python 脚本,用于解决最初的问题:保留音乐库的压缩副本。该脚本会将 .m4a 文件(假定为 ALAC)转换为 AAC 格式,除非 AAC 文件已存在并且比 ALAC 文件新。库中的 MP3 文件将被链接,因为它们已经被压缩。
请注意,中止脚本(ctrl-c)将留下半转换的文件。
我最初也想编写一个 Makefile 来处理这个问题,但由于它无法处理文件名中的空格(请参阅已接受的答案),而且编写 bash 脚本肯定会让我陷入痛苦的世界,所以 Python 就是这样。它相当简单且简短,因此应该很容易根据您的需求进行调整。
当然,这可以增强以并行执行编码。这留给读者作为练习;-)
Here's a Python script I quickly hacked together to solve the original problem: keep a compressed copy of a music library. The script will convert .m4a files (assumed to be ALAC) to AAC format, unless the AAC file already exists and is newer than the ALAC file. MP3 files in the library will be linked, since they are already compressed.
Just beware that aborting the script (ctrl-c) will leave behind a half-converted file.
I originally also wanted to write a Makefile to handle this, but since it cannot handle spaces in filenames (see the accepted answer) and because writing a bash script is guaranteed to put in me in a world of pain, Python it is. It's fairly straightforward and short, and thus should be easy to tweak to your needs.
Of course, this can be enhanced to perform the encoding in parallel. That is left as an exercise to the reader ;-)
要递归查找文件而不求助于
find
等外部依赖项,您可以使用函数。然后使用其他答案中的结果来转换文件。To find files recursively without resorting to external dependencies like
find
, you can use functions. Then use the result as in the other answer to convert the files.