دوستم یک مشکل داره و می دونه شکل مشکل چیزی است از یک کار تکراری که احتمالا در دنیای قشنگ لینوکس می شه براش راه حل های جالب پیدا کرد. صورت مساله اینه:
من تعداد زیادی فایل تبلچر (شیوه اجرای آهنگ) گیتار دارم که اسم خواننده بالاشون نوشته نشده. در نتیجه من نمی تونم سریع توی ذهنم بیارم که آهنگ چه شکلی است. مثلا وقتی بالای آهنگ نوشته شده «عسل» کمک بسیار بزرگی است اگر Ebi رو هم بالاش ببینم. این Ebi اسم فایل است پس من یکسری فایل عکس دارم که می خوام اسم فایل رو روی عکس فایل اضافه کنم
بله! لینوکس که ترکیبی از ابزارهای قدرتمند است، راه حلی عالی داره. اما یک برنامه نویس خوب همیشه اول مسائل رو در ساده ترین حالت حل می کنه و بعد مساله رو پیچیده می کنه. فرض کنیم اصولا فقط یک عکس داریم که می خوایم روش بنویسیم My Happy Text. اسم فایل هم هست Bijan Mortazavi 006. اگر بتونیم این مساله رو حل کنیم، یک قدم جلو افتادیم. در اصل من دارم مساله رو به سه بخش تقسیم می کنم:
1- اضافه کردن یک متن دلخواه به یک عکس
2- در آوردن اسم یک فایل
3- ترکیب کردن دو قدم قبلی برای هر چند تا فایل که داشتیم
قدم اول: نوشتن روی فایل
ساده است. بسته Image Magick ابزاری داره به اسم convert که می تونه تقریبا هر کاری با یک تصویر بکنه! مثلا این تصویر:
با دستور
$ convert Ebi\ 005.JPG -pointsize 43 -background Khaki label:'My Happy Text' +swap -gravity Center -append out.jpg
تبدیل می شه به:
جذاب نیست؟ بخصوص که روی تصویر چیزی ننوشتیم بلکه بالاش کمی تصویر اضافه کردیم! حالا می ریم سراغ قدم دوم.
قدم دوم: درآوردن فهرست فایلها
من احتیاج دارم اسم فایل ها رو بگیرم. اولش که ساده است؛ به لینوکس می گم همه فایل هایی که تهشون JPG هست رو بهم بده:
$ find . -name "*JPG"
./Bijan Mortazavi 005.JPG
./Ebi 015.JPG
./Ebi 018.JPG
./Ebi 016.JPG
./Darush 007.JPG
بعد کافیه بگم اون /. اول رو حذف کنه:
a$ find . -name "*JPG" | sed "s/\.\///"
Bijan Mortazavi 005.JPG
Ebi 015.JPG
Ebi 018.JPG
Ebi 016.JPG
Darush 007.JPG
و چیز دیگه که بهش احتیاج نداریم اون JPG. آخر است:
$ find . -name "*JPG" | sed "s/\.\///" | sed "s/\.JPG//"
Bijan Mortazavi 005
Ebi 015
Ebi 018
Ebi 016
Darush 007
و قدم دوم هم تموم می شه!
قدم سوم: چسبوندن قدم های قبلی
اینجا گزینه ها خیلی زیادن. بریم جلو ببینیم چی می شه. مثلا من می تونم با دستور xargs ورودی قدم دوم رو استفاده کنم. اصل صفرم برنامه نویسی جادی رو یادتونه دیگه؟ «برنامه پیچیده ای که کار می کنه، برنامه ساده ای بوده که کار می کرده» پس بذارین در ساده ترین حالت، هر کدوم از خطوط ورودی رو بدیم به یک دستور اکو:
$ find . -name "*JPG" | sed "s/\.\///" | sed "s/\.JPG//" \
| xargs -L1 -I THIS echo my command will work on \"THIS\" happily
my command will work on Bijan Mortazavi 005 happily
my command will work on Ebi 015 happily
my command will work on Ebi 018 happily
my command will work on Ebi 016 happily
my command will work on Darush 007 happily
عالی! ما قهرمانیم. الان ورودی قدم دوم رو خط به خط دادیم به دستور اکو. (سوییچ I می گه این خط ورودی باید کجای دستور قرار بگیره). بذارین یک ضرب سعی کنیم اصل برنامه رو اجرا کنیم و خروجی رو بریزیم توی دایرکتوری out و البته قبلش طبق همون اصل اول برنامه نویسی جادی، با گذاشتن یک echo جلوی دستوری که ساختیم یک تست هم می گیریم:
$ find . -name "*JPG" | sed "s/\.\///" | sed "s/\.JPG//" | xargs -L1 -I THIS echo convert \"THIS.JPG\" -pointsize 43 -background Khaki label:\'THIS\' +swap -gravity Center -append \"out/THIS.jpg\"
convert "Bijan Mortazavi 005.JPG" -pointsize 43 -background Khaki label:'Bijan Mortazavi 005' +swap -gravity Center -append "out/Bijan Mortazavi 005.jpg"
convert "Ebi 015.JPG" -pointsize 43 -background Khaki label:'Ebi 015' +swap -gravity Center -append "out/Ebi 015.jpg"
convert "Ebi 018.JPG" -pointsize 43 -background Khaki label:'Ebi 018' +swap -gravity Center -append "out/Ebi 018.jpg"
convert "Ebi 016.JPG" -pointsize 43 -background Khaki label:'Ebi 016' +swap -gravity Center -append "out/Ebi 016.jpg"
convert "Darush 007.JPG" -pointsize 43 -background Khaki label:'Darush 007' +swap -gravity Center -append "out/Darush 007.jpg"
بله ظاهرا که همه چیز عالیه. بزن بریم! اکو رو حذف می کنم ولی با اینکه دستورهای بالا درست هستن، به دلیلی که نمی دونم چیه دستورات درست اجرا نمی شن. پس کارم رو راحت می کنم:
$ find . -name "*JPG" | sed "s/\.\///" | sed "s/\.JPG//" | xargs -L1 -I THIS echo convert \"THIS.JPG\" -pointsize 43 -background Khaki label:\'THIS\' +swap -gravity Center -append \"out/THIS.jpg\" > commands.sh
$ sh commands.sh
$ ls out/
Bijan Mortazavi 001.jpg Bijan Mortazavi 005.jpg Darush 003.jpg Darush 007.jpg Darush 011.jpg Delkash 003.jpg Ebi 004.jpg Ebi 008.jpg Ebi 012.jpg Ebi 016.jpg
Bijan Mortazavi 002.jpg Bijan Mortazavi 006.jpg Darush 004.jpg Darush 008.jpg Darush 012.jpg Ebi 001.jpg Ebi 005.jpg Ebi 009.jpg Ebi 013.jpg Ebi 017.jpg
Bijan Mortazavi 003.jpg Darush 001.jpg Darush 005.jpg Darush 009.jpg Delkash 001.jpg Ebi 002.jpg Ebi 006.jpg Ebi 010.jpg Ebi 014.jpg Ebi 018.jpg
Bijan Mortazavi 004.jpg Darush 002.jpg Darush 006.jpg Darush 010.jpg Delkash 002.jpg Ebi 003.jpg Ebi 007.jpg Ebi 011.jpg Ebi 015.jpg Ebi 019.jpg
بله. دستوراتی که درست کرده بودم رو می ریزم توی یک فایل و بعد فایل رو اجرا می کنم و می بینیم که دایرکتوری out پر شده از فایل هایی که لازم بود این بلا سرشون بیاد. مثلا:
حالا می تونیم این کدها رو بدیم به دوستمون که روی سیستم خودش روی چند صد تبلچر دیگه اجرا کنه و این می شه یک فعالیت شاد و خوشحال که هم باعث می شه مهارتهای لینوکسی مون بالا بره، هم بهمون خوش بگذره هم مشکل یک دوستمون حل بشه.