create - makefile linux c
Comodines recursivos en GNU? (6)
Aquí hay un script de Python que pirateé rápidamente para resolver el problema original: mantener una copia comprimida de una biblioteca de música. La secuencia de comandos convertirá archivos .m4a (se supone que son ALAC) a formato AAC, a menos que el archivo AAC ya exista y sea más reciente que el archivo ALAC. Los archivos MP3 en la biblioteca estarán vinculados, ya que están comprimidos.
Solo tenga en cuenta que abortar el script ( ctrl-c ) dejará atrás un archivo a medio convertir.
Originalmente también quería escribir un Makefile para manejar esto, pero como no puede manejar espacios en nombres de archivos (ver la respuesta aceptada) y porque escribir un script bash me garantiza un mundo de dolor, Python sí lo es. Es bastante sencillo y breve, y por lo tanto debe ser fácil de ajustar a sus necesidades.
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])
Por supuesto, esto se puede mejorar para realizar la codificación en paralelo. Eso se deja como un ejercicio para el lector ;-)
Ha pasado un tiempo desde que utilicé make
, así que tengan paciencia conmigo ...
Tengo un directorio, flac
, que contiene archivos .FLAC. Tengo un directorio correspondiente, mp3
contiene archivos MP3. Si un archivo FLAC es más nuevo que el archivo MP3 correspondiente (o el archivo MP3 correspondiente no existe), entonces quiero ejecutar una serie de comandos para convertir el archivo FLAC en un archivo MP3 y copiar las etiquetas.
The kicker: necesito buscar el directorio flac
recursivamente y crear los subdirectorios correspondientes en el directorio mp3
. Los directorios y archivos pueden tener espacios en los nombres, y se nombran en UTF-8.
Y quiero usar make
para conducir esto.
FWIW, he usado algo así en un Makefile :
RECURSIVE_MANIFEST = `find . -type f -print`
El ejemplo anterior buscará desde el directorio actual ( ''.'' ) Para todos los "archivos simples" ( ''-type f'' ) y establecerá la variable de variable RECURSIVE_MANIFEST
en cada archivo que encuentre. A continuación, puede usar sustituciones de patrones para reducir esta lista o, alternativamente, proporcionar más argumentos en find para limitar lo que devuelve. Vea la página de manual para encontrar .
Intentaría algo en esta línea
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 "$@"
Un par de notas rápidas para make
principiantes:
- El
@
delante de los comandos evita quemake
imprima el comando antes de ejecutarlo realmente. -
$(@D)
es la parte del directorio del nombre del archivo de destino ($@
) - Asegúrese de que las líneas con comandos de shell en ellas comiencen con una pestaña, no con espacios.
Incluso si esto debe manejar todos los caracteres UTF-8 y esas cosas, fallará en espacios en nombres de archivos o directorios, ya make
utiliza espacios para separar cosas en los archivos make y no conozco una forma de evitarlo. Así que eso te deja con solo un guión de shell, me temo: - /
Mi solución se basa en la anterior, usa sed
lugar de patsubst
para patsubst
la salida de find
AND escape the spaces.
Yendo de flac / a ogg /
OGGS = $(shell find flac -type f -name "*.flac" | sed ''s/ /// /g;s/flac///ogg///;s//.flac//.ogg/'' )
Advertencias:
- Aún barfs si hay puntos y comas en el nombre del archivo, pero son bastante raros.
- El truco de $ (@ D) no funcionará (salidas de galimatías), ¡pero oggenc crea directorios para ti!
Puede definir su propia función comodín recursiva de la siguiente manera:
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
El primer parámetro ( $1
) es el nombre del directorio, y el segundo ( $2
) es el patrón que desea emparejar.
Ejemplos
Para encontrar todos los archivos C en el directorio actual:
$(call rwildcard, , *.c)
Para encontrar todos los archivos .c
y .h
en src
:
$(call rwildcard, src/, *.c *.h)
Si está utilizando Bash 4.x, puede usar una nueva opción globbing , por ejemplo:
SHELL:=/bin/bash -O globstar
list:
@echo Flac: $(shell ls flac/**/*.flac)
@echo MP3: $(shell ls mp3/**/*.mp3)
Este tipo de comodín recursivo puede encontrar todos los archivos de su interés ( .flac , .mp3 o lo que sea). O