Rekurencyjne symbole wieloznaczne w GNU make?

Minęło trochę czasu odkąd używałem make, więc bądź ze mną cierpliwy...

Mam katalog, flac, zawierającyPliki FLAC. Mam odpowiedni katalog mp3 zawierający pliki MP3. Jeśli plik FLAC jest nowszy niż odpowiedni plik MP3 (lub odpowiedni plik MP3 nie istnieje), to chcę uruchomić kilka poleceń, aby przekonwertować plik FLAC do pliku MP3 i skopiować tagi.

The kicker: muszę przeszukać katalog flac rekurencyjnie i utworzyć odpowiednie podkatalogi w katalogu mp3. Katalogi i pliki mogą mieć spacje w nazwach i są nazwane w UTF-8.

I chcę użyć make do prowadzenia tego.

Author: P Shved, 2010-03-20

6 answers

Spróbowałbym czegoś takiego

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

Kilka szybkich notek dla make początkujących:

  • @ przed poleceniami uniemożliwia make wydrukowanie polecenia przed jego uruchomieniem.
  • $(@D) jest katalogową częścią nazwy pliku docelowego($@)
  • upewnij się, że linie z poleceniami powłoki zaczynają się od tabulacji, a nie od spacji.

Nawet jeśli to powinno obsłużyć wszystkie znaki UTF-8 i takie tam, to się nie powiedzie w spacjach w nazwach plików lub katalogów, ponieważ make używa spacji do oddzielania rzeczy w plikach Makefile i nie wiem, jak to obejść. Więc zostajesz z tylko skryptem powłoki, obawiam się: - /

 95
Author: ndim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-19 12:58:53

Możesz zdefiniować własną rekurencyjną funkcję wieloznaczną w następujący sposób:

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

Pierwszy parametr ($1) to nazwa katalogu, a drugi ($2) to wzór, który chcesz dopasować.

Przykłady

Aby znaleźć wszystkie pliki C w bieżącym katalogu:

$(call rwildcard, , *.c)

Aby znaleźć wszystkie pliki .c i .h w src:

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

Źródło

 36
Author: larskholte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-15 17:37:11

FWIW, użyłem czegoś takiego w Makefile :

RECURSIVE_MANIFEST = `find . -type f -print`

Powyższy przykład wyszukuje z bieżącego katalogu ('.') dla wszystkich "plain files" ( '- type f') i ustaw zmienną RECURSIVE_MANIFEST make do każdego pliku, który znajdzie. Następnie można użyć podstawienia wzorca, aby zmniejszyć tę listę lub alternatywnie podać więcej argumentów do find, aby zawęzić to, co zwraca. Zobacz stronę podręcznika dla Znajdź .

 2
Author: Michael Shebanow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 20:09:07

Moje rozwiązanie jest oparte na powyższym, używa sed zamiast patsubst do mangle wyjścia find i ucieczki spacji.

Przejście z flac / do ogg /

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

Zastrzeżenia:

  1. nadal kłamią, jeśli w nazwie pliku są dwukropki, ale są dość rzadkie.
  2. sztuczka $(@D) nie zadziała (wypisuje bełkot), ale oggenc tworzy katalogi dla Ciebie!
 1
Author: user3199485,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-19 12:06:40

Oto skrypt Pythona, który szybko zhakowałem, aby rozwiązać oryginalny problem: zachowaj skompresowaną kopię biblioteki muzycznej. Skrypt zostanie przekonwertowany .pliki m4a (zakładane jako ALAC) do formatu AAC, chyba że plik AAC już istnieje i jest nowszy niż plik ALAC. Pliki MP3 w bibliotece zostaną połączone, ponieważ są już skompresowane.

Po prostu uważaj, że przerwanie skryptu ( ctrl-C ) pozostawi po sobie plik w połowie przekonwertowany.

Początkowo chciałem też napisać plik Makefile do obsługi tego, ale ponieważ nie może obsługiwać spacji w nazwach plików (zobacz akceptowaną odpowiedź) i ponieważ pisanie skryptu bash jest gwarantowane umieścić we mnie w świecie bólu, Python jest. Jest dość prosty i krótki, a zatem powinien być łatwy do dostosowania do swoich potrzeb.

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])

Oczywiście można to ulepszyć, aby wykonać kodowanie równolegle. To zostaje jako ćwiczenie dla czytelnika; -)

 0
Author: Brecht Machiels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-06 07:54:09

Jeśli używasz Bash 4.x, możesz użyć nowej opcji globbingu , na przykład:

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

Ten rodzaj rekurencyjnej karty wieloznacznej może znaleźć wszystkie pliki, które Cię interesują (.flac, .mp3 czy jakoś tak). O

 0
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-30 13:02:34