लोग यूनिक्स शेल सीखना चाहते हैं इसका एक सामान्य कारण बैच प्रोसेसिंग की शक्ति को अनलॉक करना है। यदि आप कई फाइलों पर क्रियाओं का कुछ सेट करना चाहते हैं, तो ऐसा करने का एक तरीका उन फाइलों पर पुनरावृति करने वाली कमांड का निर्माण करना है। प्रोग्रामिंग शब्दावली में, इसे एग्जीक्यूशन कंट्रोल कहा जाता है, और इसके सबसे सामान्य उदाहरणों में से एक for लूप है।
एक for लूप एक रेसिपी है जो विस्तार से बताती है कि आप अपने कंप्यूटर को प्रत्येक डेटा ऑब्जेक्ट (जैसे फाइल) के लिए क्या कार्रवाई करना चाहते हैं जिसे आप निर्दिष्ट करते हैं।
क्लासिक for लूप
आसान लूप आज़माने के लिए वह है जो फाइलों के संग्रह का विश्लेषण करता है। यह शायद अपने आप में एक उपयोगी लूप नहीं है, लेकिन यह खुद को साबित करने का एक सुरक्षित तरीका है कि आप एक डायरेक्टरी में प्रत्येक फाइल को व्यक्तिगत रूप से संभालने की क्षमता रखते हैं। पहले, एक डायरेक्टरी बनाकर और उसमें कुछ फाइलों की प्रतियां रखकर एक साधारण टेस्ट एनवायरनमेंट बनाएं। कोई भी फाइल शुरू में चलेगी, लेकिन बाद के उदाहरणों के लिए ग्राफिक फाइलों (जैसे JPEG, PNG, या समान) की आवश्यकता होती है। आप फोल्डर बना सकते हैं और फाइलों को फाइल मैनेजर या टर्मिनल में कॉपी कर सकते हैं:
$ mkdir example
$ cp ~/Pictures/vacation/*.{png,jpg} example
अपने नए फोल्डर में डायरेक्टरी बदलें, फिर इसमें फाइलों को सूचीबद्ध करें ताकि यह पुष्टि हो सके कि आपका टेस्ट एनवायरनमेंट वही है जिसकी आप अपेक्षा करते हैं:
$ cd example
$ ls -1
cat.jpg
design_maori.png
otago.jpg
waterfall.png
लूप में प्रत्येक फाइल के माध्यम से व्यक्तिगत रूप से पुनरावृति करने का सिंटैक्स है: एक वेरिएबल बनाएं (f फाइल के लिए, उदाहरण के लिए)। फिर उस डेटा सेट को परिभाषित करें जिसे आप वेरिएबल के माध्यम से साइकिल करना चाहते हैं। इस मामले में, * वाइल्डकार्ड कैरेक्टर का उपयोग करके वर्तमान डायरेक्टरी में सभी फाइलों के माध्यम से साइकिल चलाएं (* वाइल्डकार्ड सब कुछ से मेल खाता है)। फिर इस परिचयात्मक खंड को सेमीकोलन (;) के साथ समाप्त करें।
$ for f in * ;
आपकी प्राथमिकता के आधार पर, आप यहां Return दबाना चुन सकते हैं। शेल तब तक लूप को निष्पादित करने का प्रयास नहीं करेगा जब तक कि यह सिंटैक्टिकली पूर्ण न हो।
अगला, परिभाषित करें कि आप लूप के प्रत्येक पुनरावृति के साथ क्या होना चाहते हैं। सरलता के लिए, file कमांड का उपयोग करके प्रत्येक फाइल के बारे में थोड़ा डेटा प्राप्त करें, जिसे f वेरिएबल द्वारा दर्शाया गया है (लेकिन $ से पूर्व करके शेल को बताएं कि वेरिएबल के मान को उस चीज़ से बदल दें जो वेरिएबल वर्तमान में रखता है):
do file $f ;
एक और सेमीकोलन के साथ खंड को समाप्त करें और लूप को बंद करें:
done
शेल को वर्तमान डायरेक्टरी में सब कुछ के माध्यम से साइकिल चलाना शुरू करने के लिए Return दबाएं। for लूप प्रत्येक फाइल को एक-एक करके वेरिएबल f को असाइन करता है और आपका कमांड चलाता है:
$ for f in * ; do
> file $f ;
> done
cat.jpg: JPEG image data, EXIF standard 2.2
design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
otago.jpg: JPEG image data, EXIF standard 2.2
waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
आप इसे इस तरह भी लिख सकते हैं:
$ for f in *; do file $f; done
cat.jpg: JPEG image data, EXIF standard 2.2
design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
otago.jpg: JPEG image data, EXIF standard 2.2
waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
मल्टी-लाइन और सिंगल-लाइन दोनों प्रारूप आपके शेल के लिए समान हैं और सटीक समान परिणाम उत्पन्न करते हैं।
एक व्यावहारिक उदाहरण
यहां एक व्यावहारिक उदाहरण है कि लूप रोजमर्रा की कंप्यूटिंग के लिए कैसे उपयोगी हो सकता है। मान लें कि आपके पास छुट्टी की तस्वीरों का संग्रह है जिसे आप दोस्तों को भेजना चाहते हैं। आपकी फोटो फाइलें विशाल हैं, जिससे उन्हें ईमेल करना बहुत बड़ा हो जाता है और आपकी फोटो-शेयरिंग सेवा पर अपलोड करना असुविधाजनक होता है। आप अपनी तस्वीरों के छोटे वेब-संस्करण बनाना चाहते हैं, लेकिन आपके पास 100 तस्वीरें हैं और आप प्रत्येक फोटो को एक-एक करके छोटा करने में समय नहीं बिताना चाहते।
सबसे पहले, लिनक्स, BSD, या मैक पर अपने पैकेज मैनेजर का उपयोग करके ImageMagick कमांड इंस्टॉल करें। उदाहरण के लिए, फेडोरा और RHEL पर:
$ sudo dnf install ImageMagick
उबंटू या डेबियन पर:
$ sudo apt install ImageMagick
BSD पर, ports या pkgsrc का उपयोग करें। मैक पर, Homebrew या MacPorts का उपयोग करें।
एक बार जब आप ImageMagick इंस्टॉल कर लेते हैं, तो आपके पास फोटो पर काम करने के लिए नए कमांड का एक सेट होता है।
आपके द्वारा बनाई जाने वाली फाइलों के लिए एक डेस्टिनेशन डायरेक्टरी बनाएं:
$ mkdir tmp
प्रत्येक फोटो को उसके मूल आकार के 33% तक कम करने के लिए, इस लूप को आज़माएं:
$ for f in * ; do convert $f -scale 33% tmp/$f ; done
फिर अपने स्केल्ड फोटो देखने के लिए tmp फोल्डर में देखें।
आप लूप के भीतर कई कमांड का उपयोग कर सकते हैं, इसलिए यदि आपको फाइलों के बैच पर जटिल कार्रवाई करने की आवश्यकता है, तो आप अपने पूरे वर्कफ़्लो को for लूप के do और done स्टेटमेंट के बीच रख सकते हैं। उदाहरण के लिए, मान लें कि आप प्रत्येक प्रोसेस्ड फोटो को सीधे अपने वेब होस्ट पर शेयर्ड फोटो डायरेक्टरी में कॉपी करना चाहते हैं और फोटो फाइल को अपने स्थानीय सिस्टम से हटाना चाहते हैं:
$ for f in * ; do
convert $f -scale 33% tmp/$f
scp -i seth_web tmp/$f seth@example.com:~/public_html
trash tmp/$f ;
done
for लूप द्वारा प्रोसेस की गई प्रत्येक फाइल के लिए, आपका कंप्यूटर स्वचालित रूप से तीन कमांड चलाता है। इसका मतलब है कि यदि आप इस तरह सिर्फ 10 तस्वीरें प्रोसेस करते हैं, तो आप अपने आप को 30 कमांड और शायद उतने ही मिनट बचाते हैं।
अपने लूप को सीमित करना
लूप को हमेशा हर फाइल को देखने की ज़रूरत नहीं है। आप अपने उदाहरण डायरेक्टरी में केवल JPEG फाइलों को प्रोसेस करना चाह सकते हैं:
$ for f in *.jpg ; do convert $f -scale 33% tmp/$f ; done
$ ls -m tmp
cat.jpg, otago.jpg
या, फाइलों को प्रोसेस करने के बजाय, आपको किसी क्रिया को विशिष्ट संख्या में दोहराने की आवश्यकता हो सकती है। एक for लूप का वेरिएबल आपके द्वारा प्रदान किए गए डेटा द्वारा परिभाषित किया जाता है, इसलिए आप एक लूप बना सकते हैं जो फाइलों के बजाय नंबरों पर पुनरावृति करता है:
$ for n in {0..4}; do echo $n ; done
0
1
2
3
4
अधिक लूपिंग
अब आप अपने स्वयं के लूप बनाने के लिए पर्याप्त जानते हैं। जब तक आप लूपिंग के साथ सहज न हों, उन्हें उन फाइलों की प्रतियों पर उपयोग करें जिन्हें आप प्रोसेस करना चाहते हैं और, जितनी बार संभव हो, अंतर्निहित सुरक्षा वाले कमांड का उपयोग करें ताकि आप अपने डेटा को नष्ट करने और अपूरणीय गलतियां करने से बच सकें, जैसे गलती से फाइलों की पूरी डायरेक्टरी का नाम बदलकर एक ही नाम कर देना, प्रत्येक दूसरे को ओवरराइट कर रहा हो।
उन्नत for लूप विषयों के लिए, पढ़ते रहें।
सभी शेल बैश नहीं हैं
for कीवर्ड बैश शेल में बनाया गया है। कई समान शेल उसी कीवर्ड और सिंटैक्स का उपयोग करते हैं, लेकिन कुछ शेल, जैसे tcsh, foreach जैसे अलग कीवर्ड का उपयोग करते हैं।
tcsh में, सिंटैक्स भावना में समान है लेकिन बैश की तुलना में अधिक सख्त है। निम्न कोड नमूने में, लाइन 2 और 3 में स्ट्रिंग foreach? टाइप न करें। यह एक सेकेंडरी प्रॉम्प्ट है जो आपको सचेत करता है कि आप अभी भी अपना लूप बनाने की प्रक्रिया में हैं।
$ foreach f (*)
foreach? file $f
foreach? end
cat.jpg: JPEG image data, EXIF standard 2.2
design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
otago.jpg: JPEG image data, EXIF standard 2.2
waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
tcsh में, foreach और end दोनों को अलग-अलग लाइनों पर अकेले दिखना चाहिए, इसलिए आप बैश और समान शेल की तरह एक लाइन पर for लूप नहीं बना सकते।
find कमांड के साथ for लूप
सैद्धांतिक रूप से, आप एक ऐसा शेल ढूंढ सकते हैं जो for लूप फ़ंक्शन प्रदान नहीं करता, या आप केवल अतिरिक्त सुविधाओं के साथ एक अलग कमांड का उपयोग करना पसंद कर सकते हैं।
find कमांड for लूप की कार्यक्षमता को लागू करने का एक और तरीका है, क्योंकि यह आपके लूप में शामिल करने के लिए किन फाइलों को परिभाषित करने के कई तरीके साथ ही समानांतर प्रोसेसिंग के विकल्प प्रदान करता है।
find कमांड का उद्देश्य आपको आपकी हार्ड ड्राइव पर फाइलें ढूंढने में मदद करना है। इसका सिंटैक्स सरल है: आप उस स्थान का पाथ प्रदान करते हैं जिसे आप खोजना चाहते हैं, और find सभी फाइलों और डायरेक्टरी को ढूंढता है:
$ find .
.
./cat.jpg
./design_maori.png
./otago.jpg
./waterfall.png
आप नाम के कुछ हिस्से को जोड़कर खोज परिणामों को फ़िल्टर कर सकते हैं:
$ find . -name "*jpg"
./cat.jpg
./otago.jpg
find के बारे में महान बात यह है कि इसके द्वारा पाई गई प्रत्येक फाइल को -exec फ्लैग का उपयोग करके लूप में फीड किया जा सकता है। उदाहरण के लिए, अपने उदाहरण डायरेक्टरी में केवल PNG फोटो को स्केल डाउन करने के लिए:
$ find . -name "*png" -exec convert {} -scale 33% tmp/{} \;
$ ls -m tmp
design_maori.png, waterfall.png
-exec क्लॉज में, ब्रैकेट कैरेक्टर {} जो भी आइटम find प्रोसेस कर रहा है उसके लिए खड़े होते हैं (दूसरे शब्दों में, स्थित कोई भी फाइल जो PNG में समाप्त होती है, एक बार में एक)। -exec क्लॉज को सेमीकोलन के साथ समाप्त किया जाना चाहिए, लेकिन बैश आमतौर पर सेमीकोलन का उपयोग अपने लिए करने की कोशिश करता है। आप बैकस्लैश (\;) के साथ सेमीकोलन को "एस्केप" करते हैं ताकि find जान सके कि उस सेमीकोलन को अपने समाप्ति कैरेक्टर के रूप में व्यवहार करे।
find कमांड जो करता है उसमें बहुत अच्छा है, और यह कभी-कभी बहुत अच्छा हो सकता है। उदाहरण के लिए, यदि आप इसे किसी अन्य फोटो प्रक्रिया के लिए PNG फाइलें खोजने के लिए पुन: उपयोग करते हैं, तो आपको कुछ त्रुटियां मिलेंगी:
$ find . -name "*png" -exec convert {} -flip -flop tmp/{} \;
convert: unable to open image `tmp/./tmp/design_maori.png':
No such file or directory @ error/blob.c/OpenBlob/2643.
...
ऐसा लगता है कि find ने सभी PNG फाइलों का पता लगा लिया है—न केवल आपके वर्तमान डायरेक्टरी (.) में बल्कि उनमें भी जिन्हें आपने पहले प्रोसेस किया था और अपनी tmp सबडायरेक्टरी में रखा था। कुछ मामलों में, आप चाह सकते हैं कि find वर्तमान डायरेक्टरी के साथ-साथ उसके भीतर अन्य सभी डायरेक्टरी (और उनमें उन डायरेक्टरी) में खोजे। यह जटिल फाइल संरचनाओं (जैसे संगीत कलाकारों की डायरेक्टरी जिसमें एल्बम की डायरेक्टरी होती हैं जो संगीत फाइलों से भरी होती हैं) में विशेष रूप से एक शक्तिशाली रिकर्सिव प्रोसेसिंग टूल हो सकता है, लेकिन आप इसे -maxdepth विकल्प के साथ सीमित कर सकते हैं।
केवल वर्तमान डायरेक्टरी में PNG फाइलें खोजने के लिए (सबडायरेक्टरी को छोड़कर):
$ find . -maxdepth 1 -name "*png"
वर्तमान डायरेक्टरी प्लस सबडायरेक्टरी के एक अतिरिक्त स्तर में फाइलों को खोजने और प्रोसेस करने के लिए, अधिकतम गहराई को 1 से बढ़ाएं:
$ find . -maxdepth 2 -name "*png"
इसका डिफ़ॉल्ट सभी सबडायरेक्टरी में उतरना है।
मज़े और लाभ के लिए लूपिंग
आप जितना अधिक लूप का उपयोग करते हैं, उतना अधिक समय और प्रयास आप बचाते हैं, और जितने बड़े कार्य आप निपटा सकते हैं। आप सिर्फ एक उपयोगकर्ता हैं, लेकिन एक अच्छी तरह से सोचे-समझे लूप के साथ, आप अपने कंप्यूटर को कठिन काम करवा सकते हैं।
आप लूपिंग को किसी अन्य कमांड की तरह मान सकते हैं और इसे तब के लिए हाथ में रख सकते हैं जब आपको कई फाइलों पर एक या दो क्रियाओं को दोहराने की आवश्यकता हो। हालांकि, यह गंभीर प्रोग्रामिंग का एक वैध प्रवेश द्वार भी है, इसलिए यदि आपको किसी भी संख्या में फाइलों पर एक जटिल कार्य पूरा करना है, तो अपने दिन में से एक पल निकालकर अपने वर्कफ़्लो की योजना बनाएं। यदि आप एक फाइल पर अपना लक्ष्य प्राप्त कर सकते हैं, तो उस दोहराने योग्य प्रक्रिया को for लूप में लपेटना अपेक्षाकृत सरल है, और आवश्यक एकमात्र "प्रोग्रामिंग" यह समझ है कि वेरिएबल कैसे काम करते हैं और अनप्रोसेस्ड को प्रोसेस्ड फाइलों से अलग करने के लिए पर्याप्त संगठन। थोड़े अभ्यास के साथ, आप एक लिनक्स उपयोगकर्ता से एक लिनक्स उपयोगकर्ता बन सकते हैं जो लूप लिखना जानता है, इसलिए बाहर निकलें और अपने कंप्यूटर को अपने लिए काम करवाएं!