बैश की एक खूबसूरत लाइन की तुलना में कुछ चीजें मेरे लिए अधिक संतोषजनक हैं जो घंटों के कठिन काम को स्वचालित करती हैं।
बैश स्क्रिप्ट के साथ अपने लैपटॉप को स्वचालित रूप से फिर से बनाने में कुछ हालिया अन्वेषणों के हिस्से के रूप में (आने के लिए पोस्ट!), मैं अपने गिटहब-होस्टेड भंडारों को आसानी से एक नई मशीन पर क्लोन करने का एक तरीका खोजना चाहता था। थोड़ी सी खुदाई के बाद, मैंने एक-लाइनर लिखा जिसने बस यही किया।
फिर, अपने सभी अंडों को एक ही टोकरी में न रखने की भावना में, मैंने स्वचालित रूप से GitLab-होस्टेड बैकअप बनाने और आगे बढ़ाने के लिए एक और वन-लाइनर लिखा। ये रहे।
आपके सभी GitHub रिपॉजिटरी को क्लोन करने के लिए एक बैश वन-लाइनर
चेतावनी:आपको उन GitHub रिपॉजिटरी की सूची की आवश्यकता होगी जिन्हें आप क्लोन करना चाहते हैं। इसके बारे में अच्छी बात यह है कि यह आपको पूरी एजेंसी देता है कि आप अपनी मशीन पर केवल उन रिपॉजिटरी को चुनें जो आप चाहते हैं, बजाय पूरे हॉग में जाने के।
आप अपने 15 मिनट के कैश्ड क्रेडेंशियल के साथ HTTPS का उपयोग करके या, SSH के साथ GitHub से कनेक्ट करके, मेरी पसंदीदा विधि का उपयोग करके हर बार अपना पासवर्ड दर्ज किए बिना GitHub रिपॉजिटरी को आसानी से क्लोन कर सकते हैं। संक्षिप्तता के लिए मैं मान लूंगा कि हम बाद वाले के साथ जा रहे हैं, और हमारी SSH कुंजियाँ सेट हो गई हैं।
फ़ाइल में GitHub URL की सूची को देखते हुए gh-repos.txt
, इस तरह:
[email protected]:username/first-repository.git
[email protected]:username/second-repository.git
[email protected]:username/third-repository.git
हम दौड़ते हैं:
xargs -n1 git clone < gh-repos.txt
यह सूची के सभी रिपॉजिटरी को वर्तमान फ़ोल्डर में क्लोन करता है। यदि आप उपयुक्त URL को प्रतिस्थापित करते हैं, तो यह वही वन-लाइनर GitLab के लिए भी काम करता है।
यहाँ क्या हो रहा है?
इस वन-लाइनर के दो हिस्से हैं:इनपुट, दाईं ओर उल्टा, और वह हिस्सा जो सामान बनाता है, बाईं ओर। हम एक ही कमांड को इस तरह लिखकर इन भागों के क्रम को और अधिक सहज (शायद?) बना सकते हैं:
<gh-repos.txt xargs -n1 git clone
हमारे इनपुट की प्रत्येक पंक्ति के लिए एक कमांड चलाने के लिए, gh-repos.txt
, हम xargs -n1
. का उपयोग करते हैं . टूल xargs
इनपुट से आइटम पढ़ता है और इसे मिलने वाले किसी भी आदेश को निष्पादित करता है (यह echo
. होगा अगर यह कोई नहीं मिलता है)। डिफ़ॉल्ट रूप से, यह मानता है कि आइटम रिक्त स्थान से अलग होते हैं; नई लाइनें भी काम करती हैं और हमारी सूची को पढ़ने में आसान बनाती हैं। ध्वज -n1
बताता है xargs
1
. का उपयोग करने के लिए तर्क, या हमारे मामले में, एक पंक्ति, प्रति आदेश। हम git clone
. के साथ अपना कमांड बनाते हैं , जो xargs
फिर प्रत्येक पंक्ति के लिए निष्पादित करता है। टा-दा.
एक बैश वन-लाइनर GitLab पर कई रिपॉजिटरी बनाने और पुश करने के लिए
गिटलैब, गिटहब के विपरीत, हमें यह अच्छा काम करने देता है जहां हमें पहले एक नया भंडार बनाने के लिए वेबसाइट का उपयोग करने की आवश्यकता नहीं है। हम अपने टर्मिनल से एक नया GitLab रिपॉजिटरी बना सकते हैं। नव निर्मित भंडार डिफ़ॉल्ट रूप से निजी के रूप में सेट किया जा रहा है, इसलिए यदि हम इसे GitLab पर सार्वजनिक करना चाहते हैं, तो हमें इसे बाद में मैन्युअल रूप से करना होगा।
GitLab डॉक्स हमें git push --set-upstream
का उपयोग करके एक नया प्रोजेक्ट बनाने के लिए पुश करने के लिए कहते हैं , लेकिन मुझे बैकअप के रूप में GitLab का उपयोग करने के लिए यह बहुत सुविधाजनक नहीं लगता। जैसा कि मैं भविष्य में अपने रिपॉजिटरी के साथ काम करता हूं, मैं एक कमांड चलाना चाहता हूं जो गिटहब और दोनों को धक्का दे मेरी ओर से अतिरिक्त प्रयास के बिना GitLab।
इस बैश को एक-लाइनर काम करने के लिए, हमें GitLab (जो अभी तक मौजूद नहीं हैं) के लिए रिपॉजिटरी URL की एक सूची की आवश्यकता होगी। हम इसे आसानी से अपनी GitHub रिपॉजिटरी सूची को कॉपी करके, विम के साथ खोलकर, और एक खोज-और-प्रतिस्थापन करके कर सकते हैं:
cp gh-repos.txt gl-repos.txt
vim gl-repos.txt
:%s/\<github\>/gitlab/g
:wq
यह gl-repos.txt
produces उत्पन्न करता है , जो इस तरह दिखता है:
[email protected]:username/first-repository.git
[email protected]:username/second-repository.git
[email protected]:username/third-repository.git
हम GitLab पर इन रिपॉजिटरी को बना सकते हैं, URL को रिमोट के रूप में जोड़ सकते हैं, और अपने कोड को नए रिपॉजिटरी में चलाकर पुश कर सकते हैं:
awk -F'\/|(\.git)' '{system("cd ~/FULL/PATH/" $2 " && git remote set-url origin --add " $0 " && git push")}' gl-repos.txt
कसकर रुको और मैं इसे समझाता हूँ; अभी के लिए, ध्यान दें कि ~/FULL/PATH/
हमारे GitHub रिपॉजिटरी वाली निर्देशिका का पूरा पथ होना चाहिए।
हमें कुछ मान्यताओं पर ध्यान देना होगा:
- आपके स्थानीय मशीन पर निर्देशिका का नाम जिसमें रिपॉजिटरी शामिल है, URL में रिपॉजिटरी के नाम के समान है (यह मामला तब होगा जब इसे ऊपर एक-लाइनर के साथ क्लोन किया गया था);
- वर्तमान में प्रत्येक रिपॉजिटरी को उस शाखा में चेक आउट किया जाता है जिसे आप पुश करना चाहते हैं, अर्थात।
master
।
इन धारणाओं को संभालने के लिए वन-लाइनर का विस्तार किया जा सकता है, लेकिन यह लेखक की विनम्र राय है कि उस समय, हमें वास्तव में एक बैश स्क्रिप्ट लिखनी चाहिए।
यहां क्या हो रहा है?
हमारा बैश वन-लाइनर gl-repos.txt
में प्रत्येक पंक्ति (या URL) का उपयोग करता है इनपुट के रूप में फ़ाइल। awk
. के साथ , यह हमारी स्थानीय मशीन पर रिपॉजिटरी वाली निर्देशिका के नाम को विभाजित करता है, और हमारे बड़े कमांड को बनाने के लिए इन सूचनाओं का उपयोग करता है। अगर हमें print
करना होता awk
. का आउटपुट , हम देखेंगे:
cd ~/FULL/PATH/first-repository && git remote set-url origin --add [email protected]:username/first-repository.git && git push
cd ~/FULL/PATH/second-repository && git remote set-url origin --add [email protected]:username/second-repository.git && git push
cd ~/FULL/PATH/third-repository && git remote set-url origin --add [email protected]:username/third-repository.git && git push
आइए देखें कि हम इस कमांड को कैसे बनाते हैं।
स्ट्रिंग को awk
से विभाजित करना
टूल awk
क्षेत्र विभाजक के आधार पर इनपुट विभाजित कर सकते हैं। डिफॉल्ट सेपरेटर एक व्हाइटस्पेस कैरेक्टर है, लेकिन हम इसे -F
. पास करके बदल सकते हैं झंडा। सिंगल कैरेक्टर के अलावा, हम रेगुलर एक्सप्रेशन फ़ील्ड सेपरेटर का भी उपयोग कर सकते हैं। चूंकि हमारे रिपॉजिटरी URL का एक सेट प्रारूप होता है, इसलिए हम स्लैश कैरेक्टर /
के बीच सबस्ट्रिंग के लिए पूछकर रिपोजिटरी नामों को पकड़ सकते हैं। और URL का अंत, .git
।
इसे पूरा करने का एक तरीका हमारे रेगेक्स \/|(\.git)
. के साथ है :
\/
बच निकला है/
चरित्र;|
इसका मतलब है "या", किसी भी एक्सप्रेशन से मेल खाने के लिए awk बताना;(\.git)
हमारे URL के अंत में कैप्चर समूह है जो ".git" से मेल खाता है, एक बच गए.
चरित्र। यह थोड़ा धोखा है, क्योंकि ".git" कुछ भी सख्ती से विभाजित नहीं कर रहा है (दूसरी तरफ कुछ भी नहीं है) लेकिन यह हमारे लिए इसे दूर करने का एक आसान तरीका है।
एक बार हमने awk
बता दिया जहां विभाजित करना है, हम फील्ड ऑपरेटर के साथ सही सबस्ट्रिंग को पकड़ सकते हैं। हम अपने क्षेत्रों को $
. के साथ संदर्भित करते हैं वर्ण, फिर फ़ील्ड के कॉलम नंबर से। हमारे उदाहरण में, हम दूसरा क्षेत्र चाहते हैं, $2
. यहां बताया गया है कि सभी सबस्ट्रिंग इस तरह दिखते हैं:
1: [email protected]:username
2: first-repository
संपूर्ण स्ट्रिंग का उपयोग करने के लिए, या हमारे मामले में, संपूर्ण URL, हम फ़ील्ड ऑपरेटर $0
का उपयोग करते हैं . कमांड लिखने के लिए, हम केवल फील्ड ऑपरेटरों को रिपोजिटरी नाम और यूआरएल के लिए प्रतिस्थापित करते हैं। इसे print
के साथ चलाना जैसा कि हम निर्माण कर रहे हैं, यह सुनिश्चित करने में मदद कर सकता है कि हमारे पास सभी स्थान सही हैं।
awk -F'\/|(\.git)' '{print "cd ~/FULL/PATH/" $2 " && git remote set-url origin --add " $0 " && git push"}' gl-repos.txt
आदेश चलाना
हम system()
. के कोष्ठक के अंदर अपना आदेश बनाते हैं . इसे awk
. के आउटपुट के रूप में उपयोग करके , प्रत्येक कमांड जैसे ही इसे बनाया और आउटपुट किया जाएगा, चलाएगा। system()
फ़ंक्शन एक चाइल्ड प्रोसेस बनाता है जो हमारे कमांड को निष्पादित करता है, फिर कमांड पूरा होने के बाद वापस आ जाता है। सादे अंग्रेजी में, यह हमें हमारी मुख्य प्रक्रिया जिसमें awk
से तोड़े बिना, प्रत्येक रिपॉजिटरी पर एक-एक करके Git कमांड निष्पादित करने देता है। हमारी इनपुट फ़ाइल के साथ काम कर रहा है। ये रहा हमारा अंतिम आदेश फिर से, सभी को एक साथ रखा गया।
awk -F'\/|(\.git)' '{system("cd ~/FULL/PATH/" $2 " && git remote set-url origin --add " $0 " && git push")}' gl-repos.txt
हमारे बैकअप का उपयोग करना
GitLab URL को रिमोट के रूप में जोड़कर, हमने बाहरी रूप से होस्ट किए गए दोनों रिपॉजिटरी को पुश करने की प्रक्रिया को सरल बना दिया है। अगर हम git remote -v
run चलाते हैं हमारी एक रिपोजिटरी निर्देशिका में, हम देखेंगे:
origin [email protected]:username/first-repository.git (fetch)
origin [email protected]:username/first-repository.git (push)
origin [email protected]:username/first-repository.git (push)
अब, बस चल रहा है git push
बिना तर्क के वर्तमान शाखा को दोनों दूरस्थ रिपॉजिटरी में धकेल दिया जाएगा।
हमें यह भी ध्यान रखना चाहिए कि git pull
आम तौर पर केवल उस दूरस्थ रिपॉजिटरी से खींचने का प्रयास करेगा जिसे आपने मूल रूप से क्लोन किया था (यूआरएल चिह्नित (fetch)
ऊपर हमारे उदाहरण में)। एक ही समय में कई गिट रिपॉजिटरी से खींचना संभव है, लेकिन जटिल है, और इस पोस्ट के दायरे से बाहर है। यदि आप उत्सुक हैं, तो आरंभ करने में आपकी सहायता के लिए कई रिमोट को धक्का देने और खींचने का स्पष्टीकरण यहां दिया गया है। रिमोट पर Git दस्तावेज़ीकरण भी सहायक हो सकता है।
बैश वन-लाइनर्स की संक्षिप्तता के बारे में विस्तार से बताने के लिए
बैश वन-लाइनर्स, जब समझ में आता है, मजेदार और आसान शॉर्टकट हो सकता है। कम से कम, xargs
. जैसे टूल से अवगत होना और awk
हमारे काम में बहुत अधिक थकाऊपन को स्वचालित और कम करने में मदद कर सकता है। हालांकि, कुछ कमियां भी हैं।
समझने में आसान, रखरखाव योग्य और पहुंचने योग्य टूल के संदर्भ में, बैश वन-लाइनर्स चूसते हैं। वे आमतौर पर if
. का उपयोग करके बैश स्क्रिप्ट की तुलना में लिखने के लिए अधिक जटिल होते हैं या while
लूप, और निश्चित रूप से पढ़ने के लिए और अधिक जटिल। यह संभव है कि जब हम उन्हें लिखते हैं, तो हम कहीं एक उद्धरण या समापन कोष्ठक से चूक जाते हैं; और जैसा कि मुझे आशा है कि यह पोस्ट प्रदर्शित करता है, वे भी काफी कुछ समझा सकते हैं। तो उनका उपयोग क्यों करें?
एक केक पकाने की विधि को चरण दर चरण पढ़ने की कल्पना करें। आप विधियों और अवयवों को समझते हैं, और अपनी आपूर्ति इकट्ठा करते हैं। फिर, जैसा कि आप इसके बारे में सोचते हैं, आपको यह महसूस होना शुरू हो जाता है कि यदि आप सभी सामग्रियों को ओवन में बिल्कुल सही क्रम में फेंक देते हैं, तो केक तुरंत बन जाएगा। आप इसे आजमाएं, और यह काम करता है!
यह काफी संतोषजनक होगा, है ना?