लिनक्स फोटोग्राफर कमांड लाइन सेवानिवृत्त!

मैं चेंज -8 एम के बाद से फोटोग्राफी का शौकीन हूं। तब शुक्रवार या शनिवार (सप्ताहांत की रात को आमतौर पर प्रेस) की लंबी उम्मीदें थीं, और इससे पहले फिल्म, रसायन, फोटो पेपर (क्योंकि कमी थी) की बहुत लंबी अपेक्षाएं थीं। अब मैं बड़ी हो गई हूं, बड़ी और आलसी हो गई हूं। मेरा साबुन बॉक्स लगभग हमेशा मेरे साथ होता है: या तो एक बैग में, या कहीं मेरी जेब में। मैं सब कुछ है कि ब्याज जगा फोटो। उसी समय, प्रति दिन एक तस्वीर हो सकती है (काम से गई), और शायद एक बार में बहुत कुछ (उद्देश्यपूर्वक टहलने के लिए चला गया)। और अगर एक जानबूझकर मामले के साथ, मैं सबसे अधिक संभावना है कि जब मैं घर पहुंचूंगा तो नमक बाहर निकालूंगा, फिर अलग-अलग मामलों में मैं भूल जाऊंगा और फिर यह पता चला कि मुझे एक दर्जन अलग-अलग दिनों में ली गई तस्वीरों को सॉर्ट करने की आवश्यकता है। हाल ही में, उद्देश्यपूर्ण रूप से बाहर निकलना कम और कम हो गया, इसलिए एकल तस्वीरों की संख्या बढ़ी। और पिछले साल के लेख से प्रेरित इन दिनों में से एक पर, मैंने अपने शौक को आसान बनाने का फैसला किया। चूंकि कंप्यूटर पर लिनक्स स्थापित है (ओपनएसयूएसईएस 12.1), इसमें कोई भी अस्थिर समस्या नहीं होनी चाहिए, मैंने सोचा। और मैं चाहता था कि वह खुद को कॉपी करे और यह जरूरी नहीं कि कहीं भी प्रहार किया जाए। ठीक है, और जब से मैं एक नकली लिनक्सॉयड हूं (पहली और आखिरी स्क्रिप्ट तीसरे वर्ष में 0x0C साल पहले थी), मैं तुरंत कहूंगा कि यह काम नहीं किया।

मैं एक स्थान पर एक अलग सूची के लिए एक तिथि के साथ एक अलग सूची में फोटो रखता हूं, भले ही एक तस्वीर हो: "2009.05.20 नाइट पीटर", "2011.08.20 लवना फॉल्स", "2012.07.24 दुसरा सो रहा है।" विचार पहले से ही आ रहे हैं कि हमें कम से कम एक और स्तर की आवश्यकता है - एक वर्ष, लेकिन अभी भी सहना। मेरी या मेरी तस्वीरें नहीं (सामूहिक यात्राओं के मामले में) - यह मेरे लिए कोई फर्क नहीं पड़ता, सब कुछ घटना के लिए एक ही कैटलॉग में होगा। यदि आवश्यक हो, तो मैं अपनी तस्वीरों को कलम से ढूंढूंगा।
स्वचालित सॉर्टिंग के लिए, आपको उस क्षण को ट्रैक करने की आवश्यकता है जिसे आप वांछित मेमोरी कार्ड से कनेक्ट करते हैं और सॉर्टिंग स्क्रिप्ट चलाते हैं। लिनक्स पर, udev डेमन हार्डवेयर के लिए जिम्मेदार है। इसलिए, इसके साथ शुरू करने के लिए, हम सीखेंगे कि इसे कैसे संभालना है।

udev
udev हार्डवेयर की निगरानी करता है और प्रत्येक डिवाइस के लिए / dev निर्देशिका में अपना नोड बनाता है। यह सुविधाजनक है, लेकिन एक छोटी सी बारी है: एक ही वर्ग के उपकरणों को क्रमिक रूप से नामित किया जाएगा, जिस क्रम में वे जुड़े हुए हैं। इसलिए, प्रारंभिक विकल्प - स्क्रिप्ट पर एक बटन दबाने के लिए जो आवश्यक होने पर सब कुछ कॉपी करेगा - फिट नहीं होता है (आप कभी नहीं जानते कि कौन से अन्य ड्राइव जुड़े हुए हैं, लेकिन एक विशिष्ट ड्राइव को ट्रैक करने के लिए आपको स्क्रिप्ट को जटिल करना होगा, और मुझे कार्ड कनेक्ट करने के बाद कहीं भी काटना नहीं चाहिए) । लेकिन इसे कॉन्फ़िगर किया जा सकता है ताकि एक विशिष्ट ड्राइव वांछित बिंदु पर मुहिम की जाए - यह अच्छा है, लेकिन पर्याप्त नहीं है। इसका सबसे बड़ा प्लस: फिल्टर के लिए उपयुक्त कुछ घटनाओं के लिए एक मनमाना स्क्रिप्ट का शुभारंभ। सबसे पहले, आइए देखें कि मेमोरी कार्ड में कार्ड रीडर में डालने के तथ्य को विशिष्ट रूप से निर्धारित करने के लिए हम किन विशेषताओं और घटनाओं को संलग्न कर सकते हैं। इस खंड का अंतिम लक्ष्य एक कार्ड रीडर udev नियम फ़ाइल है।
उपकरणों की विशेषताओं को देखने के लिए, आप udvadm प्रोग्राम का उपयोग कर सकते हैं। लेकिन उसे एक डिवाइस नाम की आवश्यकता है। इसलिए, आपको पहले कार्ड रीडर में डिस्क का नाम निर्धारित करना होगा। हम सबसे आसान तरीका इस्तेमाल करेंगे। सबसे पहले, देखें कि सिस्टम में हमारे पास पहले से कौन सी ड्राइव है:
>ls -1 /dev/sd* /dev/sda /dev/sda1 /dev/sdb /dev/sdb1 /dev/sdc /dev/sdc1 /dev/sdd /dev/sdd1 /dev/sde /dev/sde1 /dev/sdf /dev/sdg /dev/sdh /dev/sdi 

हम रीडर में कार्ड डालते हैं और कमांड दोहराते हैं:
 >ls -1 /dev/sd* /dev/sda /dev/sda1 /dev/sdb /dev/sdb1 /dev/sdc /dev/sdc1 /dev/sdd /dev/sdd1 /dev/sde /dev/sde1 /dev/sdf /dev/sdg /dev/sdh /dev/sdh1 /dev/sdi 

यह देखा जा सकता है कि डाला गया कार्ड नाम / देव / sdh1 के तहत छुपा हुआ है। गुप्त रूप से, मैं कहूंगा कि अंतिम 4 डिस्क (sdf, sdg, sdh, sdi) सभी एक कार्ड रीडर हैं, और आप अपने कंप्यूटर से रीडर को कनेक्ट करने से पहले और बाद में एक ही कमांड चलाकर इसके डिस्क्स को निर्धारित कर सकते हैं, यहां तक ​​कि मेमोरी कार्ड के बिना भी (यह मेरे सामने थोड़ा सा है) बाद में यह तब आया जब उन्होंने पहले से ही वर्णित तरीके से मात्रा का नाम निर्धारित किया)।

अब हम इस कार्ड रीडर और कार्ड की विशेषताओं को देखते हैं। यह कुछ खोजने के लिए आवश्यक है जिसके लिए पाठक में कार्ड की उपस्थिति के तथ्य के अधिक या कम अस्पष्ट निर्धारण से चिपकना संभव होगा। यहां हमें उनके किसी भी डिस्क नाम की आवश्यकता होगी। यह कमांड एक udev जैसे प्रारूप में, निर्दिष्ट से लेकर रूट तक सभी उपकरणों की विशेषताओं को सूचीबद्ध करेगा:
Udevadm आउटपुट
 >udevadm info -a -n /dev/sdh1 Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device. looking at device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0/host10/target10:0:0/10:0:0:2/block/sdh/sdh1': KERNEL=="sdh1" SUBSYSTEM=="block" DRIVER=="" ATTR{partition}=="1" ATTR{start}=="2048" ATTR{size}=="153600" ATTR{ro}=="0" ATTR{alignment_offset}=="0" ATTR{discard_alignment}=="0" ATTR{stat}==" 146 4 738 319 0 0 0 0 0 319 319" ATTR{inflight}==" 0 0" looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0/host10/target10:0:0/10:0:0:2/block/sdh': KERNELS=="sdh" SUBSYSTEMS=="block" DRIVERS=="" ATTRS{range}=="16" ATTRS{ext_range}=="256" ATTRS{removable}=="1" ATTRS{ro}=="0" ATTRS{size}=="7745536" ATTRS{alignment_offset}=="0" ATTRS{discard_alignment}=="0" ATTRS{capability}=="51" ATTRS{stat}==" 1352 1239 73856 8882 4 18 22 735 0 3608 9615" ATTRS{inflight}==" 0 0" ATTRS{events}=="media_change" ATTRS{events_async}=="" ATTRS{events_poll_msecs}=="-1" looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0/host14/target14:0:0/14:0:0:2': KERNELS=="14:0:0:2" SUBSYSTEMS=="scsi" DRIVERS=="sd" ATTRS{device_blocked}=="0" ATTRS{type}=="0" ATTRS{scsi_level}=="0" ATTRS{vendor}=="Generic-" ATTRS{model}=="SD/MMC " ATTRS{rev}=="1.00" ATTRS{state}=="running" ATTRS{timeout}=="30" ATTRS{iocounterbits}=="32" ATTRS{iorequest_cnt}=="0x220" ATTRS{iodone_cnt}=="0x220" ATTRS{ioerr_cnt}=="0x21f" ATTRS{evt_media_change}=="0" ATTRS{queue_depth}=="1" ATTRS{queue_type}=="none" ATTRS{max_sectors}=="240" looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0/host14/target14:0:0': KERNELS=="target14:0:0" SUBSYSTEMS=="scsi" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0/host14': KERNELS=="host14" SUBSYSTEMS=="scsi" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0': KERNELS=="1-1:1.0" SUBSYSTEMS=="usb" DRIVERS=="usb-storage" ATTRS{bInterfaceNumber}=="00" ATTRS{bAlternateSetting}==" 0" ATTRS{bNumEndpoints}=="02" ATTRS{bInterfaceClass}=="08" ATTRS{bInterfaceSubClass}=="06" ATTRS{bInterfaceProtocol}=="50" ATTRS{supports_autosuspend}=="1" ATTRS{interface}=="Bulk-In, Bulk-Out, Interface" looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1': KERNELS=="1-1" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{configuration}=="CARD READER" ATTRS{bNumInterfaces}==" 1" ATTRS{bConfigurationValue}=="1" ATTRS{bmAttributes}=="80" ATTRS{bMaxPower}=="500mA" ATTRS{urbnum}=="10885" ATTRS{idVendor}=="0bda" ATTRS{idProduct}=="0151" ATTRS{bcdDevice}=="5195" ATTRS{bDeviceClass}=="00" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{bNumConfigurations}=="1" ATTRS{bMaxPacketSize0}=="64" ATTRS{speed}=="480" ATTRS{busnum}=="1" ATTRS{devnum}=="15" ATTRS{devpath}=="1" ATTRS{version}==" 2.00" ATTRS{maxchild}=="0" ATTRS{quirks}=="0x0" ATTRS{avoid_reset_quirk}=="0" ATTRS{authorized}=="1" ATTRS{manufacturer}=="Generic" ATTRS{product}=="USB2.0-CRW" ATTRS{serial}=="20060413092100000" looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1': KERNELS=="usb1" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{configuration}=="" ATTRS{bNumInterfaces}==" 1" ATTRS{bConfigurationValue}=="1" ATTRS{bmAttributes}=="e0" ATTRS{bMaxPower}==" 0mA" ATTRS{urbnum}=="222" ATTRS{idVendor}=="1d6b" ATTRS{idProduct}=="0002" ATTRS{bcdDevice}=="0301" ATTRS{bDeviceClass}=="09" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{bNumConfigurations}=="1" ATTRS{bMaxPacketSize0}=="64" ATTRS{speed}=="480" ATTRS{busnum}=="1" ATTRS{devnum}=="1" ATTRS{devpath}=="0" ATTRS{version}==" 2.00" ATTRS{maxchild}=="6" ATTRS{quirks}=="0x0" ATTRS{avoid_reset_quirk}=="0" ATTRS{authorized}=="1" ATTRS{manufacturer}=="Linux 3.1.10-1.16-desktop ehci_hcd" ATTRS{product}=="EHCI Host Controller" ATTRS{serial}=="0000:00:02.1" ATTRS{authorized_default}=="1" looking at parent device '/devices/pci0000:00/0000:00:02.1': KERNELS=="0000:00:02.1" SUBSYSTEMS=="pci" DRIVERS=="ehci_hcd" ATTRS{vendor}=="0x10de" ATTRS{device}=="0x077c" ATTRS{subsystem_vendor}=="0x1043" ATTRS{subsystem_device}=="0x82e7" ATTRS{class}=="0x0c0320" ATTRS{irq}=="22" ATTRS{local_cpus}=="00000000,00000000,00000000,0000000f" ATTRS{local_cpulist}=="0-3" ATTRS{numa_node}=="0" ATTRS{dma_mask_bits}=="32" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{enable}=="1" ATTRS{broken_parity_status}=="0" ATTRS{msi_bus}=="" ATTRS{companion}=="" ATTRS{uframe_periodic_max}=="100" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS=="" 

जैसा कि नोट में लिखा गया है, आप नियमों को लिखने के लिए डिवाइस के गुणों और मूल उपकरणों में से किसी एक के गुणों का उपयोग कर सकते हैं।

हम मेमोरी कार्ड के पहले खंड को जोड़ने के लिए नियम लिखेंगे (ताकि विभाजन के बिना कार्ड को तुरंत काट दिया जाए, हालांकि मैंने ऐसा करने की कोशिश नहीं की, और कैमरा पहले खंड में विशेष रूप से लिखता है)। Sdh1 मात्रा में ही कई विशिष्ट गुण नहीं हैं। यहाँ, शायद डिवाइस का नाम KERNEL == "sdh1" और इस डिवाइस का सबसिस्टम SUBSYSTEM == "ब्लॉक" है। लेकिन किसी भी फ्लैश ड्राइव में ऐसे गुण होंगे। और, जैसा कि मैंने पहले कहा था, यह तथ्य नहीं है कि अगली बार सिस्टम हमारे वॉल्यूम को sdh1 कहेगा, और अचानक मैं सामान्य रूप से xD-Picture या CompactFlash के साथ एक और कैमरा खरीदूंगा (और ये sdf, sdg, sdi होगा) - मैं नहीं चाहूंगा इसके लिए नियम फिर से लिखें। सौभाग्य से हमारे लिए, udv जोकर्स का समर्थन करता है, और इसलिए इस भाग के नियम के लिए हम अभिव्यक्ति KERNEL == "sd। 1" (या यहां तक ​​कि "sd *") लेते हैं, जिसका अर्थ मैप्ड ड्राइव का पहला वॉल्यूम होगा, और किस विशिष्ट के तहत यह एक अक्षर होगा - हम नहीं करते हैं महत्वपूर्ण बात, स्क्रिप्ट अभी भी पूरी तरह से एक जोकर के बिना नाम प्राप्त करेगी।

चलो अगले डिवाइस पर चलते हैं। /devices/pci0000:00/0000:00:02.1/usb1/1-1/1/1-1:1.0/host14/target14pg_/14code_:2/block/sdh यहां नया और यादगार है, शायद , केवल ATTRS {इवेंट} == "media_change", लेकिन फिर से, किसी भी फ्लैश ड्राइव में यह विशेषता होगी।

अगला उपकरण /devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1-1:1.0/host14/target14pg_/14_node::2 है और यहाँ ATTRS {का अधिक विशिष्ट संस्करण है मॉडल} == "एसडी / एमएमसी", लेकिन अगर हम इस विशेषता से जुड़ते हैं, तो हम केवल एसडी कार्ड का जवाब देंगे और मेमोरी कार्ड के अन्य संभावित विकल्पों की अनदेखी करेंगे। अगले तीन उपकरणों में हम फिर से कुछ भी दिलचस्प नहीं पाते हैं। निम्नलिखित डिवाइस / देवाइस / pci0000:00/0000:00:02.1/usb1/1-1 पहले से अधिक दिलचस्प है:
 SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{configuration}=="CARD READER" ATTRS{idVendor}=="0bda" ATTRS{idProduct}=="0151" ATTRS{product}=="USB2.0-CRW" ATTRS{serial}=="20060413092100000" 

विशेषताओं को देखते हुए, यह कार्ड रीडर ही है और हमें इसकी आवश्यकता है (शेष डिवाइस पहले से ही यूएसबी बस से संबंधित हैं)। कुल में, पत्राचार नियमों में, हम कार्ड रीडर की विशेषताओं और मेमोरी कार्ड की पहली मात्रा पर भरोसा करेंगे:
 ACTION=="add", KERNEL=="sd?1", SUBSYSTEMS=="usb", ATTRS{configuration}=="CARD READER", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="0151" 

और उन्होंने एक उपकरण जोड़ने के लिए एक और घटना (ACTION == "जोड़ें") डाली, क्योंकि पाठक द्वारा कार्ड से निकाले जाने के बाद नकल करना विशुद्ध रूप से शारीरिक रूप से असंभव है। मैंने सोचा: अभी भी एक एटीआरटी विशेषता {आरओ} == "0" है - इसे नियमों में भी जोड़ा जा सकता है, अन्यथा यदि डिस्क राइट-प्रोटेक्टेड है, तो कुछ भी स्थानांतरित नहीं किया जा सकता है (लेकिन यह कॉपी करना संभव होगा, हालांकि यह थोड़ा बिखरा हुआ हो सकता है अतिरिक्त निर्देशिकाएं कैमरे पर फ़ाइल प्रकार नाम टेम्पलेट के आधार पर), लेकिन मैंने इसे अभी तक स्वयं नहीं किया है।

जैसा कि आपने शायद देखा है, कुंजी ATTR / KERNEL / SUBSYSTEM / DRIVER का उपयोग डिवाइस के लिए किया जाता है, और उसके माता-पिता के लिए पहले से ही S अक्षर के अंत में होता है: ATTRS / KERNELS / SUBSYSTEMS / DRIVERS।

मेरे पास माइक्रोएसडी कार्ड के लिए एक और रीडर है, इसलिए इसकी कॉन्फ़िगरेशन में एक खाली लाइन है और आप केवल idVendor और idProduct द्वारा बाइंड कर सकते हैं। Udv रूल्स फ़ाइल के पिछले संस्करणों में से एक में (मैंने स्क्रिप्ट को अगस्त के मध्य में कहीं लिखना शुरू किया था, और अक्टूबर तक सिस्टम को अपडेट नहीं किया था और कहीं-कहीं इस अंतराल में यह विशेषता जोड़ी गई थी, और सामान्य तौर पर इस पाठक के लिए कई विशेषताओं में बदलाव हुआ ) विक्रेता और उपकरण विशेषताओं का उपयोग किया गया था, जो (थोड़ा गायब होने के बाद वे गायब हो गए) मैंने छोड़ दिया, हालांकि अब उनके लिए कोई विशेष आवश्यकता नहीं है। इस फ़िल्टर विकल्प में, यह केवल कार्ड रीडर के इस मॉडल के लिए काम करेगा और कुछ अन्य मॉडल को जोड़ने से कोई प्रभाव नहीं पड़ेगा।

हमने फ़िल्टर परिभाषित किए हैं, लेकिन हमने अभी तक कार्रवाई नहीं दी है। क्योंकि अगर हमें किसी निश्चित स्क्रिप्ट को निष्पादित करने की आवश्यकता है, तो फ़िल्टर में कार्रवाई जोड़ें:
 RUN+="/root/bin/PhotoSort.sh %k" 

स्क्रिप्ट पैरामीटर में% k - सिस्टम द्वारा उत्पन्न वॉल्यूम का नाम (डिस्क के KERNEL कुंजी में प्रदर्शित किया गया है जो sdh1 है); /root/bin/PhotoSort.sh हमारी भावी लिपि का नाम है।

Udv की अंतिम नियम फ़ाइल कुछ इस प्रकार है:
 >cat /etc/udev/rules.d/99-lumix.rules #      ACTION=="add", KERNEL=="sd?1", SUBSYSTEMS=="usb", ATTRS{configuration}=="CARD READER", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="0151", RUN+="/root/bin/PhotoSort.sh %k" #      #ACTION=="add", KERNEL=="sd?1", SUBSYSTEMS=="pci", ATTR{events}=="media_change", ATTRS{vendor}=="0x10de", ATTRS{device}=="0x077e", RUN+="/root/bin/PhotoSort.sh %k" 

अब हम इस पाठ को एक मनमाने नाम के तहत /etc/udev/rules.d/ निर्देशिका (हमें रूट विशेषाधिकारों) की आवश्यकता है (मेरे पास 99-lumix.rules) हैं। Udv डेमॉन इस निर्देशिका से वर्णमाला क्रम में फ़ाइलों को संसाधित करता है जब तक कि यह एक फिल्टर नहीं पाता है जो शर्तों से मेल खाता है। उचित नियम खोजने के बाद, फ़ाइलों का आगे प्रसंस्करण नहीं किया जाता है। इसलिए, हमारे नियम के लिए संख्या को छोटा किया जा सकता है, इसे पहले संसाधित किया जाएगा और किसी अन्य नियम द्वारा अवरुद्ध नहीं किया जाएगा।

यदि आप सभी कनेक्टेड फ्लैश ड्राइव और कार्ड का ट्रैक रखना चाहते हैं, तो आप पाठक के बाद एक स्तर कम कर सकते हैं और SUBSYSTEMS == "usb", DRIVERS == "usb- स्टोरेज" से चिपके रह सकते हैं - वे निश्चित रूप से दोनों कार्ड और फ्लैश ड्राइव पर होना चाहिए। लेकिन अभी के लिए, मैं केवल पाठक का अनुसरण करता हूं - बाकी की कोई आवश्यकता नहीं थी।

बड़ी मार
और अब हम कनेक्टेड कार्ड से फ़ोटो को सॉर्ट करने के लिए एक स्क्रिप्ट लिख रहे हैं। मूल संस्करण ने केवल संपूर्ण डिस्क को सॉर्ट करने का समर्थन किया। ऑपरेशन के दौरान, मैं मौजूदा निर्देशिकाओं (संचित) को भी संसाधित करना चाहता था, इसलिए मुझे थोड़ा बदलना और जोड़ना पड़ा। यहां हम दूसरे संस्करण पर विचार करेंगे, जो मीडिया फ़ाइलों को सॉर्ट कर सकते हैं (मीडिया फ़ाइल एक्सटेंशन स्क्रिप्ट में कमांड कमांड पैरामीटर में निर्दिष्ट हैं) डिस्क से और निर्देशिका से दोनों।

सबसे पहले, संक्षेप में इस स्क्रिप्ट के एल्गोरिथ्म के बारे में। हम निर्धारित करते हैं कि हम क्या प्रक्रिया करेंगे - वॉल्यूम या निर्देशिका। यदि वॉल्यूम है, तो इसे शुरुआत में माउंट किया जाना चाहिए (और यदि माउंट बिंदु पहले से ही लिया गया है, और इसका उपयोग केवल इस स्क्रिप्ट द्वारा किया जाता है, तो स्क्रिप्ट अपना काम पूरा कर लेगी), और अंत में अनमाउंट करना न भूलें। बढ़ते जाने के बाद, एक छिपी हुई .PhotoSort फ़ाइल की उपस्थिति जिसमें इस कार्ड के लिए सेटिंग्स संग्रहीत हैं जाँच की जाती है। इसकी अनुपस्थिति एक संकेत के रूप में कार्य करती है कि कुछ साधारण कार्ड डाले गए थे और इसके साथ कुछ भी करने की आवश्यकता नहीं थी। इस फ़ाइल में, आप डिस्क का नाम निर्दिष्ट कर सकते हैं (केवल लॉगिंग के लिए आवश्यक है - अंत में स्पष्टीकरण) और फाइलों को बचाने के लिए निर्देशिका, अगर मानक फिट नहीं है (मैंने मोबाइल फोन के लिए एक अलग भंडारण बनाने के बारे में सोचा)। निर्यात निर्देशिका को कमांड लाइन पर या udv रूल्स फ़ाइल में स्क्रिप्ट के दूसरे पैरामीटर के रूप में भी निर्दिष्ट किया जा सकता है।

फिर, दी गई और उपनिर्देशिकाओं की सभी मीडिया फाइलें (क्योंकि कैमरे अलग-अलग निर्देशिकाओं में फ़ोटो सहेजते हैं जो हमारे लिए पहले ज्ञात नहीं हैं) उन्हें उस समय तक सॉर्ट किया जाना चाहिए, जब वे बनाए गए थे। एक पकड़ है: लिनक्स में ऐसी कोई चीज नहीं है जिस समय एक फ़ाइल बनाई गई थी, लेकिन फ़ाइल के अंतिम उपयोग का समय है, और जब चित्रों में हेरफेर किया जाता है, तो इसे अपडेट किया जाता है, इसलिए आप इस पर भरोसा नहीं कर सकते। फ़ाइल नाम भी असंभव है: DSC08655.JPG 02.05 को MOV08554.MPG के बाद 29.04 से जाना चाहिए, जो कि 1911 से P1170007.JPG के बाद संसाधित किया जाना चाहिए। यह समस्या विशेष रूप से तीव्र है अगर हमारे पास विभिन्न निर्माताओं के कई कैमरे हैं जो एक घटना (उर्फ "पार्टी") की तस्वीरें लेते हैं। EXIF हमारी सहायता के लिए आता है - अन्य बातों के अलावा, इसमें DateTimeOriginal और CreateDate विशेषताएँ हैं (उनके बीच कुछ अंतर है: कम से कम वीडियो फ़ाइलों में पहले वाला नहीं है और यदि किसी कारण से यह पढ़ा नहीं गया है, तो दूसरा पढ़ा जाएगा) और ये सामान्य स्थितियों में विशेषताएँ नहीं बदलतीं। लेकिन मुझे नहीं पता कि इन विशेषताओं द्वारा छांटे गए, सभी नेस्टेड निर्देशिकाओं से फ़ाइलों को कैसे पढ़ना है, इसलिए इन विशेषताओं द्वारा क्रमबद्ध किया जाता है, इसलिए सभी फ़ाइलों को एक लूप में बदल दिया जाता है (एक्सफ़िटूल स्वयं ऐसा कर सकता है, लेकिन मैंने लॉग के लिए एक लूप छोड़ दिया), स्नैपशॉट या वीडियो बनाने के लिए समय जोड़ना नाम से (ताकि बाद में आप फ़ाइल नाम से कालानुक्रमिक क्रम में सॉर्ट कर सकें)।

दूसरा चक्र फाइलों को निर्देशिकाओं में वितरित करता है: एक नई निर्देशिका तब बनाई जाती है जब वर्तमान फ़ाइल और पिछले एक के बीच का ब्रेक पांच घंटे (5 * 60 * 60) से अधिक हो जाता है - यही कारण है कि हमने कालानुक्रमिक क्रम में फ़ाइलों को सॉर्ट किया। पाँच बजे छत से एक आकृति है। मेरे पास एक घटना से चित्र नहीं थे ताकि शॉट्स के बीच का अंतराल इस समय से अधिक हो। POI के बीच लंबी यात्रा के साथ, सैर भी होती थी, लेकिन सड़क पर पाँच घंटे से भी कम समय लगता था, और अगर ज्यादा होता तो पहले से ही एक और शहर होता। अलग-अलग दिन शादियाँ और छुट्टियां बीत रही थीं, और हालाँकि तारीख बदल गई, लेकिन आयोजन वही रहा। इसलिए, जबकि एक छोटी सी ब्रेक उसी निर्देशिका में पिछली फ़ाइल के रूप में सहेजी जाती है। निर्देशिका का नाम YYYYMMDD_HH के रूप में सेट किया गया है - एक ही दिन की दो घटनाओं के कारण घड़ी (नई घटना की पहली फ़ाइल से ली गई) को निर्देशिका नाम में जोड़ा जाता है, अन्यथा जब हम दूसरे दिन जाते हैं तो हमें एक ही निर्देशिका का नाम मिलता है, और हालाँकि इसका निर्माण विफल हो जाएगा, लेकिन आगे इसे बचाने के लिए। फ़ाइलें उसी निर्देशिका में कार्यान्वित की जाएंगी।

जो कुछ भी होता है वह लॉग को लिखा जाता है (यह मैंने स्क्रिप्ट की कार्यप्रणाली की जांच की है), साथ ही फाइलों को डिस्क पर वापस करने के लिए आदेश (यह डिबगिंग के लिए उपयोगी था - मैंने फ़ाइल का एक टुकड़ा निष्पादित किया और परीक्षण मीडिया फाइलें अपने पुराने नामों के साथ नक्शे पर वापस आ गईं)। अतिरिक्त प्रसंस्करण (रोटेशन, कमी, हस्ताक्षर) - मैं उपयोग नहीं करता, वैसे भी मैं उन्हें देख सकता हूं, उन्हें हटा सकता हूं और यह सब कर सकता हूं (मैं तस्वीरों पर हस्ताक्षर नहीं करता हूं)। वह स्थान जहां यह किया जा सकता है, स्क्रिप्ट पाठ में एक टिप्पणी द्वारा इंगित किया गया है।
स्क्रिप्ट ही:
 >cat /root/bin/PhotoSort.sh #!/bin/bash #/root/bin/PhotoSort.sh #requires: bash,coreutils,findutils,exiftool,sed,util-linux #cat /etc/udev/rules/99-lumix.rules ##      #ACTION=="add", KERNEL=="sd?1", SUBSYSTEMS=="usb", ATTRS{configuration}=="CARD READER", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="0151", RUN+="/root/bin/PhotoSort.sh %k" ##      ##ACTION=="add", KERNEL=="sd?1", SUBSYSTEMS=="pci", ATTR{events}=="media_change", ATTRS{vendor}=="0x10de", ATTRS{device}=="0x077e", RUN+="/root/bin/PhotoSort.sh %k" #      udev #udevadm info -a -p $(udeadm info -q path -n /dev/sd*)  udevadm info -a -n /dev/sd* #http://www.arccomm.ru/OpenSource/Dev/udev.html if [[ -z "$1" ]] then echo             , echo      echo $(basename "$0") Source [DestDir] echo Source -    ,    echo DestDir -  ,     echo   ,    echo   ,      .PhotoCopy echo             echo    -   \( \) echo : echo $(basename "$0") sdd1 -    /dev/sdd1. echo         sdd1     .PhotoCopy echo        echo $(basename "$0") . ~/Photo -     \(.\)       echo    ~/Photo/  exit 1 #    fi if [[ ${1:0:1} == "/" || ${1:0:1} == "." || ${1:0:1} == "~" ]] then #   if [[ -d "$1" ]] then disk="$1" else echo    exit 2 #     fi else #   #   dev="/dev/$1" if [[ ! -e "$dev" ]] then #   ,     (      ,   ) exit 0 fi #    disk="/mnt/photo" fi #    if [[ ! -z "$2" ]] then #     photo="$2" else photo="/mnt/temp/Photo" #  ,  fi sphoto="" #    #         photodir="" # -:         -  log="/var/log/photosort.log" #      lastfiletime=0 #     curfiletime=0 #   -  #export XAUTHORITY="/home/%username%/.Xauthority" #export DISPLAY=:0.0 #notify-send Photoes "FlashCard found" #     - ?  - ,         if [[ -n "$dev" ]] then grep -q "$disk" /etc/mtab if [[ $? -eq 0 ]] #     , grep  0 then #  -   echo "#=- $(date -u +%Y.%m.%d\ %T)    -=#" exit 10 #   ,    -   fi #  if [[ ! -d "$disk" ]] then #     - mkdir "$disk" &>>"$log" echo "#"    "$disk" >> "$log" fi mount -t vfat -o noatime,rw,noexec,users,iocharset=utf8 "$dev" "$disk" &>> "$log" if [[ ! -e "$disk"/.PhotoCopy ]] then #       ,    umount "$disk" &>> "$log" exit 0 #   ,       ,       fi # :      $2,         #  -   ( /dev)    (  root) sphoto=$(head -n1 "$disk"/.PhotoCopy) #           ,        if [[ ${sphoto:0:1} == "/" && -d "$sphoto" ]] then #    ,    ,   photo="$sphoto" fi sphoto=$(tail -n1 "$disk"/.PhotoCopy) #        echo $(date -u +%Y.%m.%d\ %T)    "$sphoto" >> "$log" else if [[ ! -z "$2" ]] then photo="$2" #    fi log="./PhotoSort.log" #      echo "#" $(date -u +%Y.%m.%d\ %T)    "$photo" >> "$log" echo cd $(pwd) >> "$log" #     ,            fi #       # NB!:     - ,     #   ,       , #    (     ) #    (     -  ) for file in $(find "$disk" -type f \( -name '*.JPG' -o -name '*.MOV' -o -name '*.MPG' -o -name '*.THM' -o -name '*.MP4' -o -name '*.AVI' \) -and -not -name '*_*' -and -not -name '* *') do # exiftool   : # Date/Time Original : 2011:07:30 15:35:52 #     20110730153552 curfiletime=$(exiftool -DateTimeOriginal "$file" | cut -d: -f2- | sed 's/[:\ ]//g') #    if [[ $curfiletime == "" ]] then curfiletime=$(exiftool -CreateDate "$file" | cut -d: -f2- | sed 's/[:\ ]//g') #    fi mv "$file" $(dirname "$file")/"$curfiletime"_$(basename "$file") &>> "$log" #  echo mv $(dirname "$file")/"$curfiletime"_$(basename "$file") "$file" >> "$log" #     done #      # (      ,       -  -     ,  ,  ) for file in $(find "$disk" -type f -name '*.JPG' -o -name '*.MOV' -o -name '*.MPG' -o -name '*.THM' -o -name '*.MP4' -o -name '*.AVI' | sort) do # exiftool  ,               ,     curfiletime=$(exiftool -DateTimeOriginal "$file" | sed -r 's/^.+: ([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\1-\2-\3 \4:\5:\6/g') if [[ $curfiletime == "" ]] then curfiletime=$(exiftool -CreateDate "$file" | sed -r 's/^.+: ([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\1-\2-\3 \4:\5:\6/g') fi curfiletime=$(date -d "$curfiletime" +%s) #       if (( $curfiletime - $lastfiletime > 5*60*60 )) #        : 5*60*60 ,           then photodir=$(date -d @$curfiletime +%Y.%m.%d_%H) #       if [[ ! -d "$photo"/"$photodir" ]] #    - then mkdir "$photo"/"$photodir" &>> "$log" chown nobody:users "$photo"/"$photodir" &>> "$log" chmod 0777 "$photo"/"$photodir" &>> "$log" echo "#" $(date -u +%Y.%m.%d\ %T)    "$photodir" >> "$log" fi lastfiletime="$curfiletime" fi echo "#" $(date -u +%Y.%m.%d\ %T)   "$file"  "$photo"/"$photodir"/$(basename "$file") >> "$log" echo copy "$photo"/"$photodir"/$(basename "$file") "$file" >> "$log" #        -  (/ , gps   ) mv "$file" "$photo"/"$photodir"/ &>> "$log" chown nobody:users "$photo"/"$photodir"/$(basename "$file") &>> "$log" chmod 0666 "$photo"/"$photodir"/$(basename "$file") &>> "$log" done if [[ -n "$dev" ]] then echo $(date -u +%Y.%m.%d\ %T)   >> "$log" #    umount "$disk" &>> "$log" fi exit 0 

कुछ बिंदुओं के लिए स्पष्टीकरण: एक्सफ़ॉटलम "दिनांक / समय मूल: 2011: 07: 30 15:35:52" फॉर्म के तार देता है, इस स्ट्रिंग को "20110730153552" में परिवर्तित किया जाना चाहिए (नोट: इंटरनेट उन उदाहरणों से भरा है जहां विभाजक एक बृहदान्त्र नहीं है, लेकिन एक ऊर्ध्वाधर है सुविधा - देखें कि आपके पास क्या है):

 curfiletime=$(exiftool -DateTimeOriginal "$file" | cut -d: -f2- | sed 's/[:\ ]//g') 

कटौती - पहले कोलन के बाद सब कुछ काट देता है, और sed परिणामी स्ट्रिंग से सभी रिक्त स्थान और कॉलोन को हटा देगा। मुझे यकीन है कि आप केवल sed कर सकते हैं, लेकिन RegExp बहुत अनुकूल नहीं है।

 curfiletime=$(exiftool -DateTimeOriginal "$file" | sed -r 's/^.+: ([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\1-\2-\3 \4:\5:\6/g') 

उसी पंक्ति को "2011-07-30 15:35:52" में रूपांतरित करता है। फिर, शायद एक और अधिक सुरुचिपूर्ण समाधान मौजूद है। यह इतना है कि तिथि को एक तिथि के रूप में संसाधित किया जा सकता है (एक मनमाना प्रारूप में, स्ट्रिंग को इसमें नहीं खिसकाया जा सकता है)।

के उपयोग
स्क्रिप्ट निर्दिष्ट निर्देशिका और उसमें संलग्न सब कुछ (एक मेमोरी कार्ड के लिए इसकी जड़ और सब कुछ गहरा होगा) को एक के रूप में संसाधित करता है।

 ./PhotoSort.sh sdh1 
इस प्रकार, sdh1 ड्राइव को सॉर्ट करने के लिए udev से स्क्रिप्ट को कॉल किया जाता है। इस मामले में, इसकी जड़ में सेटिंग्स के साथ फाइल की जांच की जाएगी। डिस्क हमें दी गई थी या निर्देशिका पहले चरित्र द्वारा निर्धारित की जाती है: यदि यह ~ / या है। - एक निर्देशिका का मतलब है, अन्यथा - एक डिस्क।

 ./PhotoSort.sh ~/AllFromParty 
और इसलिए आप ~ (AllFromParty (स्वयं सहित) में संलग्न सभी निर्देशिकाओं से सभी फ़ोटो और वीडियो फ़ाइलों को सॉर्ट कर सकते हैं। स्क्रिप्ट (फोटो = "/ mnt / अस्थायी / फोटो") में निर्दिष्ट डिफ़ॉल्ट निर्देशिका में सब कुछ सहेजा जाएगा। यदि स्रोत निर्देशिका में कई कैमरों से फाइलें होती हैं, तो इस तथ्य के कारण फ़ाइल नामों में कुछ विसंगति हो सकती है कि कैमरों के बीच का समय सिंक्रनाइज़ नहीं है, या यहां तक ​​कि कभी भी सेट नहीं किया गया है। जो विभिन्न कैमरों से विभिन्न निर्देशिकाओं में फ़ाइलों के वितरण का कारण बन सकता है। फिर, छँटाई करने से पहले, आपको EXIF ​​टैग में समय समायोजित करने की आवश्यकता है: exiftool "-DateTimeOriginal + = 00.00.0000 02:37:30" * .JPG - वर्तमान समय में सभी JPG फ़ाइलों के लिए भविष्य में DateTimeoriginal टैग में 2:37:30 तक का समय बदल देगा।

 ./PhotoSort.sh ~/AllFromParty /media/backup/Photoes 
ऊपर जैसा ही है, लेकिन सब कुछ / मीडिया / बैकअप / फ़ोटोज़ निर्देशिका में सहेजा जाएगा


  1. : , KDE , , . , , ( ).
  2. , . ini-.
  3. . . RUN+= , - . udev' , KDE , — . , .
  4. .PhotoSort udev' . , root - . - . (, ) .
  5. , dosfslabel . udev - . - .
  6. : . Caanoo — .PhotoSort .
  7. - , RO .
  8. . , - , ?

Bash-
HOWTO: udev
udev. ( )

Source: https://habr.com/ru/post/In158371/


All Articles