109

使ってから久しぶりmakeですので、ご容赦ください...

flac.FLACファイルを含むディレクトリがあります。mp3MP3ファイルを含む対応するディレクトリがあります。FLACファイルが対応するMP3ファイルよりも新しい場合(または対応するMP3ファイルが存在しない場合)、一連のコマンドを実行してFLACファイルをMP3ファイルに変換し、タグをコピーします。

キッカー:flacディレクトリを再帰的に検索し、対応するサブディレクトリをディレクトリに作成する必要がありますmp3。ディレクトリとファイルの名前にはスペースを含めることができ、UTF-8で名前が付けられます。

そして、私はこれを推進するために使用したいと思いますmake

4

6 に答える 6

133

私はこれらの線に沿って何かを試みます

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 "$@"

make初心者向けの簡単なメモ:

  • コマンドの前にあると、実際に実行する前に@コマンドを出力できなくなります。make
  • $(@D)ターゲットファイル名のディレクトリ部分です($@
  • シェルコマンドが含まれる行が、スペースではなくタブで始まることを確認してください。

これがすべてのUTF-8文字などを処理する必要がある場合でも、ファイル名またはディレクトリ名のスペースで失敗します。これは、makeスペースを使用してmakefile内の文字を区切るためであり、これを回避する方法がわかりません。シェルスクリプトだけが残りますので、恐れ入ります:-/

于 2010-03-20T13:35:06.317 に答える
70

次のように、独自の再帰ワイルドカード関数を定義できます。

rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))

最初のパラメーター($1)はディレクトリのリストであり、2番目のパラメーター()は$2照合するパターンのリストです。

例:

現在のディレクトリ内のすべてのCファイルを検索するには:

$(call rwildcard,.,*.c)

.c内のすべての.hファイルを検索するにはsrc

$(call rwildcard,src,*.c *.h)

この関数は、この記事の実装に基づいていますが、いくつかの改善が加えられています。

于 2013-08-15T17:37:11.633 に答える
4

Bash 4.xを使用している場合は、次のような新しいグロブオプションを使用できます。

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

この種の再帰ワイルドカードは、関心のあるすべてのファイル( .flac.mp3など)を見つけることができます。O

于 2015-05-10T18:01:33.423 に答える
2

FWIW、私はMakefileでこのようなものを使用しました:

RECURSIVE_MANIFEST = `find . -type f -print`

上記の例では、現在のディレクトリ('。')からすべての「プレーンファイル」('-type f')をRECURSIVE_MANIFEST検索し、見つかったすべてのファイルにmake変数を設定します。次に、パターン置換を使用してこのリストを減らすか、またはさらに多くの引数をfindに指定して、返されるものを絞り込むことができます。検索については、マニュアルページを参照してください。

于 2011-12-03T20:09:07.717 に答える
2

私の解決策は上記の解決策に基づいており、のsed代わりにANDpatsubstの出力をマングルしfindてスペースをエスケープします。

flac/からogg/に移行

OGGS = $(shell find flac -type f -name "*.flac" | sed 's/ /\\ /g;s/flac\//ogg\//;s/\.flac/\.ogg/' )

警告:

  1. ファイル名にセミコロンが含まれている場合でも、バーフは表示されますが、非常にまれです。
  2. $(@ D)トリックは機能しません(出力はぎこちない)が、oggencはあなたのためにディレクトリを作成します!
于 2014-01-15T18:52:50.917 に答える
2

これは、元の問題を解決するためにすばやく一緒にハッキングしたPythonスクリプトです。音楽ライブラリの圧縮コピーを保持します。AACファイルがすでに存在し、ALACファイルよりも新しい場合を除き、スクリプトは.m4aファイル(ALACと想定)をAAC形式に変換します。ライブラリ内のMP3ファイルはすでに圧縮されているため、リンクされます。

スクリプト(ctrl-c)を中止すると、半分変換されたファイルが残ることに注意してください。

私ももともとこれを処理するためにMakefileを書きたかったのですが、ファイル名のスペースを処理できず(受け入れられた答えを参照)、bashスクリプトを書くことは苦痛の世界に私を置くことが保証されているので、Pythonはそうです。それはかなり単純で短いので、ニーズに合わせて簡単に調整できるはずです。

from __future__ import print_function


import glob
import os
import subprocess


UNCOMPRESSED_DIR = 'Music'
COMPRESSED = 'compressed_'

UNCOMPRESSED_EXTS = ('m4a', )   # files to convert to lossy format
LINK_EXTS = ('mp3', )           # files to link instead of convert


for root, dirs, files in os.walk(UNCOMPRESSED_DIR):
    out_root = COMPRESSED + root
    if not os.path.exists(out_root):
        os.mkdir(out_root)
    for file in files:
        file_path = os.path.join(root, file)
        file_root, ext = os.path.splitext(file_path)
        if ext[1:] in LINK_EXTS:
            if not os.path.exists(COMPRESSED + file_path):
                print('Linking {}'.format(file_path))
                link_source = os.path.relpath(file_path, out_root)
                os.symlink(link_source, COMPRESSED + file_path)
            continue
        if ext[1:] not in UNCOMPRESSED_EXTS:
            print('Skipping {}'.format(file_path))
            continue
        out_file_path = COMPRESSED + file_path
        if (os.path.exists(out_file_path)
            and os.path.getctime(out_file_path) > os.path.getctime(file_path)):
            print('Up to date: {}'.format(file_path))
            continue
        print('Converting {}'.format(file_path))
        subprocess.call(['ffmpeg', '-y', '-i', file_path,
                         '-c:a', 'libfdk_aac', '-vbr', '4',
                         out_file_path])

もちろん、これを拡張して、エンコードを並行して実行することもできます。それは読者の練習問題として残されています;-)

于 2016-12-25T19:38:20.270 に答える