জিএনইউতে রিকার্সিভ ওয়াইল্ডকার্ড তৈরি?


96

আমি যেহেতু কিছুক্ষণ ব্যবহার করেছি makeতাই আমার সাথে সহ্য করুন ...

flac.FLAC ফাইল সমন্বিত একটি ডিরেক্টরি পেয়েছি । আমি mp3এমপি 3 ফাইল সমন্বিত একটি ডিরেক্টরি পেয়েছি । যদি কোনও এফএলএসি ফাইল সংশ্লিষ্ট এমপি 3 ফাইলের চেয়ে নতুন হয় (বা সম্পর্কিত MP3 ফাইল উপস্থিত নেই), তবে আমি FLAC ফাইলকে একটি এমপি 3 ফাইলে রূপান্তর করতে এবং গুগল ট্যাগগুলি অনুলিপি করতে একটি গুচ্ছ কমান্ড চালাতে চাই।

কিকার: আমার flacডিরেক্টরিটি পুনরাবৃত্তভাবে অনুসন্ধান করতে হবে এবং ডিরেক্টরিতে সংশ্লিষ্ট সাব-ডিরেক্টরি তৈরি করতে হবে mp3। ডিরেক্টরি এবং ফাইলগুলির নাম ফাঁকা থাকতে পারে এবং ইউটিএফ -8 এ নামকরণ করা হয়েছে।

এবং আমি এটি makeচালনা করতে ব্যবহার করতে চাই ।


4
এই উদ্দেশ্যে মেক নির্বাচন করার কোনও কারণ? আমি ভাবলাম বাশ স্ক্রিপ্ট লেখা সহজ হবে

4
@ নীল, প্যাটার্ন-ভিত্তিক ফাইল সিস্টেম রূপান্তর হিসাবে মেকের ধারণাটি আসল সমস্যার কাছে যাওয়ার সর্বোত্তম উপায়। সম্ভবত এই পদ্ধতির বাস্তবায়নগুলির এর সীমাবদ্ধতা রয়েছে তবে makeখালি তুলনায় এটি বাস্তবায়নের আরও কাছাকাছি bash
পি মার্ভেড

4
@ পাভেল ওয়েল, একটি shস্ক্রিপ্ট যা ফ্ল্যাক ফাইলগুলির তালিকায় চলে ( find | while read flacname), mp3nameএটি থেকে একটি তৈরি করে, " এমকেডির-পি " চালায় dirname "$mp3name"এবং তারপরে if [ "$flacfile" -nt "$mp3file"]রূপান্তরিত "$flacname"করা "$mp3name"আসলে যাদু নয়। makeভিত্তিক সমাধানের তুলনায় আপনি যে একমাত্র বৈশিষ্ট্যটি হারাচ্ছেন তা হ'ল Nসমান্তরালে ফাইল রূপান্তর প্রক্রিয়া চালানোর সম্ভাবনা make -jN
ndim

4
@ এন্ডিম আমি এই প্রথম শুনেছি যে মেকের সিনট্যাক্সটিকে "সুন্দর" :-) হিসাবে বর্ণনা করা যেতে পারে

4
makeফাইলের নামগুলিতে ফাঁকা স্থান ব্যবহার এবং এটি পরস্পরবিরোধী প্রয়োজনীয়তা। সমস্যা ডোমেনের জন্য উপযুক্ত একটি সরঞ্জাম ব্যবহার করুন।
জেনস

উত্তর:


121

আমি এই লাইন বরাবর কিছু চেষ্টা করবে

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)লক্ষ্য ফাইল নামের ডিরেক্টরি অংশ ( $@)
  • শেল কমান্ডগুলির সাথে রেখাগুলি ফাঁকা দিয়ে নয়, কোনও ট্যাব দিয়ে শুরু হয়েছে তা নিশ্চিত করুন।

এমনকি এটি যদি সমস্ত ইউটিএফ -8 অক্ষর এবং স্টাফগুলি পরিচালনা করে তবে এটি ফাইল বা ডিরেক্টরি নামগুলির makeফাঁকে ফাঁকে ব্যর্থ হয়ে যায়, কারণ মেকফিলগুলিতে স্টাফ পৃথক করার জন্য স্পেস ব্যবহার করে এবং এর আশপাশে কাজ করার কোনও উপায় সম্পর্কে আমি অবগত নই। সুতরাং এটি আপনাকে কেবল একটি শেল স্ক্রিপ্ট দিয়ে ফেলেছে, আমি ভয় করি: - /


এখানেই আমি যাচ্ছিলাম ... জয়ের জন্য দ্রুত আঙ্গুলগুলি। যদিও দেখে মনে হচ্ছে আপনি চতুর সাথে কিছু করতে সক্ষম হবেন vpath। আজকের এক যে অবশ্যই অধ্যয়ন করা উচিত।
dmckee --- প্রাক্তন-মডারেটর বিড়ালছানা

4
ডিরেক্টরিতে যখন নামগুলিতে স্পেস থাকে তখন কাজ করার জন্য উপস্থিত হয় না।
রজার লিপস

বুঝতে পারিনি যে findনামগুলি পুনরাবৃত্তি করার জন্য আমাকে শেল আউট করতে হবে ...
রজার লিপস্বেবি

4
@ পলকনোভা: চালান make -jN। সমান্তরালে চলতে হবে Nএমন রূপান্তর সংখ্যা ব্যবহার করার জন্য make। সতর্কতা: make -jএকটি ছাড়াই দৌড়ানো Nসমান্তরালে একবারে সমস্ত রূপান্তর প্রক্রিয়া শুরু করবে যা কাঁটা বোমার সমতুল্য হতে পারে।
ndim

4
@ অ্যাড্রিয়ান: .PHONY: allলাইনটি জানিয়েছে যে allটার্গেটের রেসিপিটি কার্যকর করতে হবে এমনকি যদি allসমস্ত ফাইলের চেয়েও নতুন বলা হয় $(MP3_FILES)
ndim

56

আপনি আপনার নিজের পুনরাবৃত্ত ওয়াইল্ডকার্ড ফাংশনটিকে এভাবে সংজ্ঞায়িত করতে পারেন:

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

প্রথম প্যারামিটারটি $1ডিরেক্টরিগুলির একটি তালিকা এবং দ্বিতীয়টি ( $2) আপনার সাথে তাল মিলাতে চান এমন নিদর্শনগুলির একটি তালিকা।

উদাহরণ:

বর্তমান ডিরেক্টরিতে সমস্ত সি ফাইল খুঁজে পেতে:

$(call rwildcard,.,*.c)

এতে সমস্ত ফাইল .cএবং .hফাইলগুলি সন্ধান করতে src:

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

এই ফাংশনটি কয়েকটি উন্নতি সহ এই নিবন্ধটি থেকে বাস্তবায়নের ভিত্তিতে তৈরি ।


এটি আমার পক্ষে কাজ করে না বলে মনে হচ্ছে। আমি সঠিক ফাংশনটি অনুলিপি করেছি এবং এটি এখনও পুনরাবৃত্তভাবে দেখাবে না।
জেরোইন

4
আমি জিএনইউ মেক 3.81 ব্যবহার করছি এবং এটি আমার পক্ষে কাজ করে বলে মনে হচ্ছে। যদিও কোনও ফাইলনামের মধ্যে ফাঁকা স্থান থাকলে এটি কাজ করবে না। মনে রাখবেন যে ফাইলগুলি যে নামটি দেয় সেগুলির বর্তমান ডিরেক্টরিটির সাথে সম্পর্কিত পাথ রয়েছে, এমনকি যদি আপনি কেবল একটি সাব ডিরেক্টরিতে ডিরেক্টরি ফাইল করেন।
larskholte

4
এটি সত্যই উদাহরণস্বরূপ, এটি makeএকটি টুরিং টার পিট (দেখুন এখানে: yosefk.com/blog/fun-at-the-turing-tar-pit.html )। এটি এমনকি কঠিন নয়, তবে একটি এটি পড়তে হবে: gnu.org/software/make/manual/html_node/Call-Function.html এবং তারপরে " পুনরুক্তি বুঝতে"। আপনার এটি বার বার লিখতে হয়েছিল, ভার্ভ্যাটিম অর্থে; এটি "সাবডির থেকে স্বয়ংক্রিয়ভাবে জিনিস অন্তর্ভুক্ত করা" এর প্রতিদিনের বোঝাপড়া নয়। এটি আসল অভিজ্ঞতা EC তবে মনে রাখবেন - "পুনরুক্তি বুঝতে, আপনাকে পুনরাবৃত্তিটি বুঝতে হবে"।
টমাসজ গ্যান্ডর

@ টমাসজান্ডার আপনি পুনরাবৃত্তি বুঝতে হবে না। আপনাকে পুনরাবৃত্তি বুঝতে হবে এবং এটি করতে আপনাকে প্রথমে পুনরাবৃত্তি বুঝতে হবে।
ব্যবহারকারী1129682

আমার খারাপ, আমি একটি ভাষাগত মিথ্যা-বন্ধুর হয়ে পড়েছিলাম for মন্তব্যগুলি এত দীর্ঘ সময় পরে সম্পাদনা করা যায় না, তবে আমি আশা করি প্রত্যেকটি পয়েন্টটি পেয়েছে। এবং তারা পুনরাবৃত্তি বুঝতে।
টমাসজ গ্যান্ডার

2

FWIW, আমি একটি মধ্যে ভালো কিছু ব্যবহার করেছি Makefile নামক :

RECURSIVE_MANIFEST = `find . -type f -print`

উপরের উদাহরণটি সমস্ত "প্লেইন ফাইল" ( '-প্রকার এফ' ) জন্য বর্তমান ডিরেক্টরি ( '।' ) থেকে অনুসন্ধান করবে এবং এটি খুঁজে পাওয়া প্রতিটি ফাইলের জন্য মেক ভেরিয়েবল সেট করবে । তারপরে আপনি এই তালিকাটি হ্রাস করতে প্যাটার্ন বিকল্পগুলি ব্যবহার করতে পারেন বা বিকল্প হিসাবে এটি কী ফিরে আসে সংকীর্ণ করতে আরও যুক্তি সরবরাহ করতে পারে । জন্য man পৃষ্ঠা দেখুন খোঁজRECURSIVE_MANIFEST


1

আমার সমাধানটি উপরেরটির উপর ভিত্তি করে তৈরি হয়েছে এবং আউটপুটটি ফাঁক করে ফাঁকা স্থানগুলি ছাড়ানোর sedপরিবর্তে ব্যবহার করে ।patsubstfind

ফ্ল্যাক / ওজিজি / এ যাচ্ছেন

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

গুহাত:

  1. ফাইলনেমে আধা-কলোন থাকলেও বার্ফস, তবে সেগুলি খুব বিরল।
  2. @ (@ ডি) কৌশলটি কাজ করবে না (গিব্বারিশ আউটপুটস), তবে ওগেনসিচ আপনার জন্য ডিরেক্টরি তৈরি করে!

1

মূল সমস্যাটি সমাধান করতে আমি দ্রুত একসাথে হ্যাক করেছি এখানে একটি পাইথন স্ক্রিপ্ট রয়েছে: একটি সংগীত গ্রন্থাগারের একটি সংকুচিত অনুলিপি রাখুন। স্ক্রিপ্টটি .m4a ফাইলগুলিকে (এএলএসি হিসাবে ধরে নেওয়া হয়) এএসি ফরম্যাটে রূপান্তর করবে, যদি না এএসি ফাইল ইতিমধ্যে উপস্থিত থাকে এবং এটি এএলএসি ফাইলের চেয়ে নতুন না হয়। গ্রন্থাগারের এমপি 3 ফাইলগুলি লিঙ্কযুক্ত হবে, যেহেতু তারা ইতিমধ্যে সংকুচিত হয়েছে।

কেবল সাবধান থাকুন যে স্ক্রিপ্টটি বাতিল করা ( ctrl-c) আধা-রূপান্তরিত ফাইলের পিছনে ফেলে দেবে।

আমি মূলত এটি হ্যান্ডেল করার জন্য একটি মেকফিলও লিখতে চেয়েছিলাম তবে যেহেতু এটি ফাইলের নামগুলিতে ফাঁকা স্থানগুলি পরিচালনা করতে পারে না (স্বীকৃত উত্তর দেখুন) এবং যেহেতু ব্যাশ স্ক্রিপ্টটি লিখতে আমার ব্যথার জগতে রাখার গ্যারান্টিযুক্ত তাই পাইথন এটি। এটি মোটামুটি সোজা এবং সংক্ষিপ্ত এবং এর ফলে আপনার প্রয়োজনগুলিতে টুইঙ্ক করা সহজ হওয়া উচিত।

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

অবশ্যই, সমান্তরালভাবে এনকোডিং সম্পাদন করতে এটি বাড়ানো যেতে পারে। এটি পাঠকের অনুশীলন হিসাবে ছেড়ে গেছে ;-)


0

যদি আপনি ব্যাশ ৪.x ব্যবহার করে থাকেন তবে আপনি একটি নতুন গ্লোববিং বিকল্প ব্যবহার করতে পারেন , উদাহরণস্বরূপ:

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

রিকার্সিভ ওয়াইল্ডকার্ড এই ধরনের আপনার আগ্রহের (এর সব ফাইল খুঁজে পেতে পারেন .flac , .mp3 বা যাই হোক না কেন)। ও


4
আমার কাছে, এমনকি মাত্র $ (ওয়াইল্ডকার্ড ফ্ল্যাক / ** / *। ফ্ল্যাক) কাজ করছে বলে মনে হচ্ছে। ওএস এক্স,
জ্ঞান

4
আমি চেষ্টা করেছি $ (ওয়াইল্ডকার্ড। আমি মনে করি না যে মেকটি আসলে ** সমর্থন করে এবং আপনি একে অপরের পাশে দুটি * গুলি ব্যবহার করলে এটি ব্যর্থ হয় না।
lahwran

@ আলাহরান আপনার বাশ শেলের মাধ্যমে কমান্ড চাওয়ার সময় এবং গ্লোবস্টারের বিকল্পটি সক্ষম করে রাখা উচিত । হতে পারে আপনি জিএনইউ মেক বা অন্য কিছু ব্যবহার করছেন না। পরিবর্তে আপনি এই বাক্য গঠনটিও ব্যবহার করে দেখতে পারেন । কিছু পরামর্শের জন্য মন্তব্য পরীক্ষা করুন। অন্যথায় এটি নতুন প্রশ্নের জিনিস
কেনরব

@ কোনরব না, আমি আপনার জিনিসটিও চেষ্টা করে দেখিনি কারণ আমি এই বিশেষ জিনিসটির জন্য শেল আহরণ এড়াতে চেয়েছিলাম। আমি আকৌপ্পির প্রস্তাবিত জিনিসটি ব্যবহার করছিলাম। আমি যে জিনিসটি দিয়েছিলাম সেটিকে লার্শহোল্টের জবাবের মতো লাগছিল, যদিও আমি এটি অন্য কোথাও থেকে পেয়েছি কারণ এখানে দেওয়া মন্তব্যগুলি বলেছিল যে এটি একটি সম্পূর্ণরূপে ভেঙে গেছে।
শ্রাগ

@ আল্লাহরান এক্ষেত্রে **কাজ করবে না, কারণ বর্ধিত গ্লোব্বিং একটি বাশ / জেডশ জিনিস।
কেনারব
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.