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.
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żliwiamake
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ę: - /
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)
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ź .
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:
- nadal kłamią, jeśli w nazwie pliku są dwukropki, ale są dość rzadkie.
- sztuczka $(@D) nie zadziała (wypisuje bełkot), ale oggenc tworzy katalogi dla Ciebie!
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; -)
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
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