SSD Nodes Learn 🎉 VPS $5.50/माह से
गाइड Matt Connorलेखक: Matt Connor

Bash globbing और wildcards कैसे काम करते हैं

Bash globbing के जरिए shell कैसे patterns को filenames में बदलता है, इसे विस्तार से समझें। nullglob, dotglob, globstar और extglob negation के सटीक उपयोग के तरीके यहाँ जानें।

कमांड चलने से पहले Bash globbing क्या करता है

Bash globbing वह प्रक्रिया है जिसमें shell, *.log जैसे pattern को वास्तविक filenames की एक sorted सूची में बदल देता है, और यह काम कमांड शुरू होने से पहले होता है। rm *.log कभी भी rm को कोई pattern नहीं भेजता है। Bash directory को पढ़ता है, मेल खाने वाले नामों को रखता है, उन्हें sort करता है, और फिर प्रत्येक नाम को एक अलग argument के रूप में लेकर rm को चलाता है। rm प्रोग्राम को यह पता नहीं चल पाता कि कभी कोई pattern इस्तेमाल किया गया था।

globbing के बारे में लगभग हर आश्चर्यजनक बात इसी एक तथ्य से जुड़ी है। मिलान (matching) का काम shell द्वारा उस समय मौजूद फाइलों के आधार पर किया जाता है, और कमांड को केवल तैयार सूची ही दिखाई देती है। इसके लिए औपचारिक शब्द pathname expansion है। Globbing एक आम बोलचाल का शब्द है, और दोनों का अर्थ एक ही है।

अभ्यास के लिए एक छोटा ट्री बनाएँ

नीचे दिए गए सभी उदाहरण एक ही फाइलों पर चलते हैं। उन्हें एक अस्थायी निर्देशिका (temporary directory) में बनाएँ, ताकि आपके महत्वपूर्ण डेटा को कोई खतरा न हो और सफाई (cleanup) केवल एक कमांड से हो सके।

lab=$(mktemp -d)
cd "$lab"
mkdir -p logs archive/2025 archive/2026
touch app.log app.log.1 app.log.2 app.log.10 error.log debug.LOG
touch notes.txt notes.md README 'weekly report.log'
touch .env .apprc
touch logs/nginx.log logs/nginx.log.1
touch archive/2025/dec.log archive/2026/jan.log

mktemp -d एक नई निर्देशिका बनाता है और उसका पथ (path) लौटाता है, और $(...) उस पथ को lab वेरिएबल में कैप्चर करता है। यदि यह सिंटैक्स आपके लिए नया है, तो कमांड सब्स्टीट्यूशन कमांड के आउटपुट को कैसे कैप्चर करता है इसे विस्तार से समझाता है।

जो आपने बनाया है उसे देखें, और अपने शेल की जाँच करें, क्योंकि अंत में एक नोट वर्जन पर निर्भर करता है:

ls -a
bash --version

यहाँ सब कुछ bash 4.0 और उसके बाद के वर्जन्स पर काम करता है। अंत के पास दिया गया globskipdots नोट bash 5.2 और उसके बाद के वर्जन्स पर लागू होता है, जो अगस्त 2026 तक वर्तमान Ubuntu और Debian रिलीज़ में उपलब्ध है।

पूरे लेख में उपयोग किया गया प्रीव्यू कमांड printf '%s\n' PATTERN है। यह प्रति पंक्ति एक मैच प्रिंट करता है और डिस्क पर कुछ भी नहीं बदलता है, इसलिए किसी भी ऐसे पैटर्न पर इसे चलाना सुरक्षित है जिसके बारे में आप सुनिश्चित नहीं हैं।

तीन वाइल्डकार्ड: स्टार, प्रश्नवाचक चिह्न और ब्रैकेट

  • * किसी भी वर्णों की श्रृंखला का मिलान करता है, जिसमें खाली श्रृंखला भी शामिल है।
  • ? ठीक एक वर्ण का मिलान करता है।
  • [...] ब्रैकेट के अंदर दिए गए सेट में से ठीक एक वर्ण का मिलान करता है।
printf '%s\n' *.log
printf '%s\n' app.log.?
printf '%s\n' app.log.[0-9]
printf '%s\n' notes.*
printf '%s\n' *

दूसरी पंक्ति की तुलना आपके द्वारा बनाई गई फ़ाइल सूची से करें। ? केवल एक वर्ण के लिए है और उससे अधिक कुछ नहीं, इसलिए दो अंकों वाला सफ़िक्स उस पैटर्न में नहीं आता है। इसे app.log.[0-9]* तक बढ़ाएं और अंतर देखने के लिए इसे फिर से चलाएं।

तीनों वाइल्डकार्ड पर दो नियम लागू होते हैं। कोई भी वाइल्डकार्ड कभी भी / का मिलान नहीं करता है, इसलिए पैटर्न एक डायरेक्टरी स्तर के भीतर ही रहता है। और एक शुरुआती . को अक्षरशः टाइप करना पड़ता है, इसलिए * से शुरू होने वाला पैटर्न हर छिपी हुई फ़ाइल (hidden name) को छोड़ देता है। यही दूसरा नियम कारण है कि rm * आपकी dotfiles को नहीं छूता है।

Glob परिणाम वर्तमान locale के कोलेशन ऑर्डर का उपयोग करके क्रमबद्ध किए जाते हैं, जो कि वर्ण-दर-वर्ण टेक्स्ट सॉर्ट है। इसलिए 10 का सफ़िक्स 2 के सफ़िक्स से पहले आता है, क्योंकि तुलना कभी भी किसी को संख्या के रूप में नहीं पढ़ती है। printf '%s\n' app.log.* और फिर ls -v app.log.* चलाएं और दोनों की तुलना करें: ls -v एम्बेडेड संख्याओं को उनके मान के अनुसार क्रमबद्ध करता है, और sort -V पाइपलाइन में वही कार्य करता है।

Character classes और ranges

Brackets के अंदर आप एक list, range, या negation लिख सकते हैं।

  • [ch] एक character से match करता है, जो या तो c हो या h
  • [a-f] a से f तक की range में किसी एक character से match करता है।
  • [!0-9] किसी ऐसे character से match करता है जो digit नहीं है। [^0-9] का अर्थ भी यही है।
printf '%s\n' [dn]*
printf '%s\n' *.[A-Z]*
printf '%s\n' [A-Z]*

Ranges वह हिस्सा हैं जो अलग-अलग मशीनों के बीच असंगत हो सकते हैं। Range का resolution plain ASCII के बजाय current locale के collation order के साथ होता है, इसलिए कुछ systems पर [a-z] uppercase अक्षरों से भी match कर सकता है। Bash में एक globasciiranges option होता है जो plain ASCII order को force करता है, और हाल के builds में यह default रूप से enabled होता है, इसलिए यह मान लेने के बजाय कि यह enabled है, shopt globasciiranges के साथ इसकी जाँच करें। एक script जिसे हर जगह एक ही तरह से match करना है, वह खुद order को pin कर सकती है। इसके लिए script में सबसे ऊपर एक अलग line पर LC_ALL=C set करें, जो हर range को वापस plain byte order पर ले आता है।

यह assignment अपने आप में एक स्वतंत्र command होना चाहिए। यदि इसे prefix के रूप में लिखा जाए, तो LC_ALL=C ls [a-z]* केवल ls के लिए locale set करता है और किसी अन्य चीज़ के लिए नहीं। shell, ls के शुरू होने से पहले ही अपने locale में pattern को expand कर चुका होता है, जो कि पहले section में बताए गए नियम को फिर से दर्शाता है।

Brace expansion और globbing एक नहीं हैं

Braces देखने में wildcard जैसे लगते हैं, लेकिन इनका व्यवहार उनसे बिल्कुल अलग होता है। Brace expansion, globbing से बहुत पहले चलता है और यह कभी भी disk को नहीं देखता।

echo file{1,2,3}.txt
echo {01..10}
echo {a..e}
echo {0..20..5}

इनमें से कोई भी file मौजूद नहीं है, फिर भी expansion हो जाता है। यही मुख्य अंतर है: glob filesystem से सवाल पूछता है, जबकि brace केवल text generate करता है। यही कारण है कि चीजें खोजने के बजाय उन्हें बनाने के लिए braces सही tool हैं।

mkdir -p site/{css,js,img}
cp app.log{,.bak}
touch report-{2025,2026}-{01,02}.csv

cp app.log{,.bak} दो शब्दों, app.log और app.log.bak में expand होता है, क्योंकि comma से पहले का खाली item मूल text को दोहराता है। {01..10} अपनी zero padding बनाए रखता है, क्योंकि किसी भी endpoint पर leading zero होने से bash हर generate होने वाली संख्या को समान चौड़ाई (width) में pad कर देता है।

Expansion का क्रम उस विफलता को भी समझाता है जिसका सामना लोग अक्सर करते हैं। Bash पहले braces को expand करता है, फिर variables को, और अंत में pathname expansion करता है।

n=5
echo {1..$n}

जब तक $n एक संख्या बनता है, तब तक brace expansion पूरा हो चुका होता है, इसलिए कोई range नहीं बनती। seq 1 "$n" का उपयोग करें, या for ((i=1; i<=n; i++)) के रूप में लिखा गया C-style loop इस्तेमाल करें।

जब कोई पैटर्न किसी से मैच न करे तो क्या होता है

यह विफलता का पहला प्रकार है, और यह हर किसी को एक बार जरूर फंसाता है। डिफ़ॉल्ट रूप से, bash एक अनमैच्ड (unmatched) पैटर्न को वैसा ही छोड़ देता है। वह शब्द कमांड तक बिल्कुल वैसे ही पहुँचता है जैसे आपने उसे टाइप किया था, इसलिए कमांड को *, ., t, m और p अक्षर प्राप्त होते हैं और वह उन्हें एक फाइलनाम के रूप में मानने की कोशिश करता है।

printf '%s\n' *.tmp

printf के साथ यह हानिरहित है। लेकिन ऐसी कमांड के साथ यह हानिरहित नहीं है जो फाइलें बनाती है। ऐसी डायरेक्टरी में जहाँ कोई .tmp फाइल न हो, touch *.tmp चलाने पर एक ऐसी फाइल बनती है जिसका नाम शाब्दिक रूप से *.tmp होता है, और बाद में उसे डिलीट करने के लिए कोट्स (quoting) की आवश्यकता होती है ताकि शेल उसे फिर से एक्सपैंड न करे: rm -- '*.tmp'

दो शेल विकल्प इस नियम को बदलते हैं। प्रत्येक को ऐसे पैटर्न के साथ आजमाएं जो किसी से मैच नहीं करता, फिर उसे अनसेट (unset) कर दें।

shopt -s nullglob
printf '%s\n' *.tmp
shopt -u nullglob

shopt -s failglob
printf '%s\n' *.tmp
shopt -u failglob

nullglob एक अनमैच्ड पैटर्न को पूरी तरह से हटा देता है, इसलिए कमांड आपके द्वारा लिखे गए तर्कों (arguments) की तुलना में कम तर्कों के साथ चलती है। लूप के दौरान आप यही चाहते हैं। nullglob बंद होने पर, for f in *.tmp अपनी बॉडी को एक बार चलाता है और f में शाब्दिक पैटर्न होता है, जो लगभग हर उस स्क्रिप्ट में एक बग है जो ऐसा करती है। nullglob चालू होने पर, बॉडी शून्य बार चलती है।

nullglob का अपना खतरा है, क्योंकि सभी तर्कों के बिना भी कमांड चलती रहती है। ls *.nope एक खाली ls बन जाता है, जो पूरी डायरेक्टरी को लिस्ट कर देता है। grep -l needle *.nope, grep -l needle बन जाता है, जिसके पास पढ़ने के लिए कोई फाइल नहीं होती, इसलिए वह स्टैंडर्ड इनपुट पर प्रतीक्षा करता है और ऐसा लगता है जैसे वह फ्रीज हो गया हो। जिस लूप में आवश्यकता हो, उसी के आसपास nullglob को चालू करें और बाद में बंद कर दें।

failglob दूसरा रास्ता अपनाता है: एक अनमैच्ड पैटर्न एक त्रुटि है, bash इसकी रिपोर्ट करता है, और कमांड बिल्कुल नहीं चलती। यह एक इंटरैक्टिव शेल के लिए एक अच्छी सेटिंग है, क्योंकि यह गलत टाइप किए गए पैटर्न को rm को शाब्दिक नाम के रूप में भेजे जाने से रोकता है।

Hidden files: dotglob

shopt -s dotglob
printf '%s\n' *
shopt -u dotglob

इस ब्लॉक को चलाएं और लिस्टिंग की तुलना पहले वाले printf '%s\n' * से करें। dotglob लीडिंग डॉट के नियम को हटा देता है, इसलिए * अब छिपी हुई फाइलों (hidden names) के साथ भी मैच करता है। dotglob के तहत . और .. प्रविष्टियां हमेशा बाहर रहती हैं।

dotglob के बिना, छिपी हुई फाइलों तक पहुँचने का सामान्य तरीका .* है, और यह पहले खतरनाक हुआ करता था। bash 5.2 से पुराने वर्ज़न पर, .* भी . और .. के साथ मैच करता था, इसलिए chmod -R 755 .* जैसा कोई भी रिकर्सिव कमांड सीधे पैरेंट डायरेक्टरी में चला जाता था। Bash 5.2 ने globskipdots विकल्प जोड़ा, जो डिफ़ॉल्ट रूप से सक्षम है और . तथा .. को हर एक्सपेंशन से बाहर रखता है। इस पर भरोसा करने से पहले shopt globskipdots चलाकर जाँच लें, क्योंकि पुराने सिस्टम में यह सुविधा नहीं होगी।

globstar: पूरी डायरेक्टरी ट्री में मैच करना

shopt -s globstar
printf '%s\n' **/*.log
printf '%s\n' **/
shopt -u globstar

जब globstar सेट होता है, तो ** जो एक पूर्ण पाथ कंपोनेंट बनाता है, वह किसी भी गहराई पर मौजूद फाइलों और डायरेक्टरीज़ से मैच करता है, जिसमें शून्य स्तर भी शामिल है। इसलिए **/*.log वर्तमान डायरेक्टरी के साथ-साथ logs/ और archive/ के अंतर्गत आने वाली हर चीज़ को कवर करता है। ट्रेलिंग स्लैश वाला **/ केवल डायरेक्टरीज़ से मैच करता है, जो ट्री की संरचना देखने का एक तेज़ तरीका है।

यदि globstar सेट नहीं है, तो ** एक सामान्य * की तरह व्यवहार करता है और केवल एक डायरेक्टरी तक सीमित रहता है। इस विकल्प को बंद करके उसी पैटर्न को चलाएं और तुलना करें: यदि कहीं से कॉपी किया गया रिकर्सिव पैटर्न आपकी अपेक्षा से बहुत कम परिणाम देता है, तो आमतौर पर यही कारण होता है। हर bash में globstar डिफ़ॉल्ट रूप से बंद रहता है।

एक सीमा जिसके बारे में जानना उपयोगी है: ** डायरेक्टरीज़ के सिम्बॉलिक लिंक्स (symbolic links) का अनुसरण नहीं करता है। सिम्बॉलिक लिंक्स के साथ जुड़ी हुई ट्री के लिए इसके बजाय find -L की आवश्यकता होती है।

nocaseglob, उन नामों के लिए जो केस (case) के मामले में मेल नहीं खाते

shopt -s nocaseglob
printf '%s\n' *.log
shopt -u nocaseglob

nocaseglob फाइलनाम मिलान (filename matching) को केस के प्रति संवेदनशील नहीं बनाता है, इसलिए एक अपरकेस .LOG सफिक्स एक लोअरकेस .log पैटर्न से मेल खा जाता है। इस लिस्टिंग की तुलना पहले सेक्शन की लिस्टिंग से करें। इस विकल्प को तुरंत वापस बंद कर दें, क्योंकि इसे चालू रखने पर यह उस शेल में बाद में आने वाले हर कमांड के लिए मिलान के तरीके को बदल देता है, और एक घंटे बाद इसे डीबग करना काफी भ्रमित करने वाला हो सकता है।

nocaseglob केवल फाइलनाम विस्तार (filename expansion) पर लागू होता है। case स्टेटमेंट या डबल ब्रैकेट टेस्ट के अंदर पैटर्न मिलान के लिए संबंधित विकल्प nocasematch है, और इन दोनों को अलग-अलग सेट किया जाता है।

extglob: वे patterns जो "यह नहीं" कह सकते हैं

Extended patterns डिफ़ॉल्ट रूप से बंद होते हैं। इन्हें एक अलग लाइन पर चालू करें:

shopt -s extglob

इसके पाँच रूप हैं, जिनमें से प्रत्येक | द्वारा अलग किए गए patterns की एक सूची लेता है:

  • ?(list) शून्य या एक बार आने वाले मिलान को दर्शाता है।
  • *(list) शून्य या अधिक बार आने वाले मिलान को दर्शाता है।
  • +(list) एक या अधिक बार आने वाले मिलान को दर्शाता है।
  • @(list) विकल्पों में से ठीक एक का मिलान करता है।
  • !(list) किसी भी ऐसी चीज़ का मिलान करता है जो किसी विकल्प से मेल नहीं खाती।

एक extended pattern को ऐसे shell द्वारा पढ़ा जाना चाहिए जिसमें यह विकल्प पहले से चालू हो, इसलिए नीचे दिया गया batch एक छोटी script में जाता है जिसे bash -O extglob के साथ शुरू किया जाता है। -O flag नई shell द्वारा फ़ाइल की एक भी लाइन पढ़ने से पहले एक shopt विकल्प सेट करता है, जिसका अर्थ है कि इसमें मौजूद हर pattern सही ढंग से पार्स होता है। इस section का अंतिम पैराग्राफ वह कारण है कि क्रम (ordering) मायने क्यों रखता है।

cat > patterns.sh <<'EOF'
printf '%s\n' @(app|error).log
printf '%s\n' app.log.+([0-9])
printf '%s\n' *.@(md|txt)
printf '%s\n' !(*.log)
printf '%s\n' !(*.log|*.md|README)
EOF
bash -O extglob patterns.sh

+([0-9]) का अर्थ है एक या अधिक अंक, इसलिए यह किसी भी लंबाई के numbered suffix को कवर करता है। यह पहले बताई गई ? सीमा का समाधान है, और इसे देखने के लिए दोनों patterns को एक के बाद एक चलाना सार्थक है।

Negation (नकारात्मक) रूप "सब कुछ सिवाय" का उत्तर है, और यही extglob को सक्षम करने का मुख्य कारण है। इसके बारे में दो बातें लोगों को आश्चर्यचकित करती हैं।

यह फ़ाइलों के साथ-साथ directories का भी मिलान करता है, इसलिए ls !(*.log) परिणाम में directory नाम के बजाय किसी भी directory की सामग्री को सूचीबद्ध करता है। नामों को स्वयं देखने के लिए ls -d, या printf पूर्वावलोकन का उपयोग करें।

यह अन्य सभी globs की तरह dot नियम का भी पालन करता है, इसलिए !(*.log) हर उस दृश्य नाम को कवर करता है जो .log पर समाप्त नहीं होता है। छिपे हुए नामों के लिए dotglob को भी सेट करना आवश्यक है।

!(...) में ! glob negation है। इसका history expansion और bang character से कोई संबंध नहीं है, जो एक अलग सुविधा है और एक अलग चरण पर चलती है।

एक और समस्या, और यह parse समय पर होती है। Bash किसी भी कमांड को चलाने से पहले उसे पूरा पार्स करता है, इसलिए एक ही लाइन पर extglob को सक्षम करना और extended pattern का उपयोग करना विफल हो जाता है: pattern तब पार्स हो जाता है जब विकल्प अभी भी बंद होता है। shopt -s extglob को अपनी अलग लाइन पर, patterns से पहले, और script के शीर्ष के पास रखें। Function body को तब पार्स किया जाता है जब function परिभाषित किया जाता है, इसलिए विकल्प को definition से पहले चालू होना चाहिए, न कि call से पहले। Shell को bash -O extglob के साथ शुरू करना, जैसा कि ऊपर दिए गए batch में किया गया है, किसी भी parsing के शुरू होने से पहले क्रम को व्यवस्थित कर देता है।

शेल पैटर्न को expand करता है, कमांड नहीं

यह विफलता का दूसरा प्रकार है, और यह कई तरह की त्रुटियों (bugs) का कारण बनता है।

grep -l needle *.log
find . -name '*.log'
find . -name *.log

पहली पंक्ति bash को मिलान (matching) करने देती है, और grep को फाइलनामों की एक सूची प्राप्त होती है। दूसरी पंक्ति पैटर्न को कोट (quote) करती है, इसलिए find को पांच अक्षर *.log प्राप्त होते हैं और वह शुरुआती बिंदु के नीचे हर गहराई पर अपना स्वयं का मिलान करता है। तीसरी पंक्ति में त्रुटि है: bash पहले पैटर्न को केवल वर्तमान डायरेक्टरी के विरुद्ध expand करता है, इसलिए find को एक विशिष्ट नाम खोजने के लिए कहा जाता है। एक मिलान वाली डायरेक्टरी में यह चुपचाप गलत चीज खोजता है। दो या अधिक मिलान होने पर, find एक उपयोग त्रुटि (usage error) की रिपोर्ट करता है, क्योंकि अतिरिक्त नाम वहां आ जाते हैं जहां उसे एक एक्सप्रेशन की अपेक्षा होती है।

नियम संक्षिप्त है। यदि पैटर्न कमांड के लिए है, तो उसे कोट करें। यदि यह शेल के लिए है, तो उसे बिना कोट के छोड़ दें। यही विभाजन tar और rsync में --exclude पैटर्न, और grep में --include फिल्टर पर लागू होता है।

Globs रेगुलर एक्सप्रेशन नहीं होते हैं, भले ही वे कुछ अक्षर साझा करते हों। एक glob में, * का अर्थ है अक्षरों की कोई भी श्रृंखला। एक रेगुलर एक्सप्रेशन में, * का अर्थ है उससे पहले आने वाली चीज शून्य या अधिक बार, इसलिए grep '*.log' कुछ ऐसा मांगता है जो दिखने में बिल्कुल अलग है।

Variables भी संचालन के इसी क्रम का पालन करते हैं। Globbing, वेरिएबल एक्सपेंशन के बाद चलता है, इसलिए पैटर्न रखने वाला एक अनकोटेड वेरिएबल डायरेक्टरी के विरुद्ध expand हो जाता है।

pat='*.log'
printf '%s\n' $pat
printf '%s\n' "$pat"

अनकोटेड होने पर, bash वेरिएबल के परिणाम को glob करता है। कोटेड होने पर, पैटर्न literal रहता है। इसका एक संबंधित परिणाम है जिस पर आपको भरोसा करना चाहिए: globbing द्वारा उत्पन्न शब्द कभी भी स्पेस पर दोबारा split नहीं होते हैं, इसलिए for f in *.log स्पेस वाले फाइलनाम को एक नाम के रूप में संभालता है, जबकि for f in $(ls *.log) उस नाम को दो शब्दों में तोड़ देता है। सीधे glob पर लूप चलाएं।

किसी destructive pattern को चलाने से पहले उसका पूर्वावलोकन (preview) करें

कभी भी rm को उस पहले कमांड के रूप में न इस्तेमाल करें जिसके साथ आप कोई नया pattern आज़मा रहे हों। pattern को किसी सुरक्षित कमांड के साथ चलाएं, सूची पढ़ें, और फिर केवल लाइन के शुरू में दिए गए कमांड को बदलें।

target='!(*.log)'
printf '%s\n' $target
ls -ld -- $target
rm -- $target

pattern को एक बार target में लिखने से तीनों लाइनें अलग नहीं होतीं, और $target को जानबूझकर बिना quotes के रखा गया है, क्योंकि यही bash को इसे expand करने की अनुमति देता है। printf '%s\n' प्रति लाइन एक नाम प्रिंट करता है और किसी भी फाइल को नहीं छूता। ls -ld प्रत्येक entry को स्वयं दिखाता है, न कि directories की सामग्री को, और mode कॉलम यह दर्शाता है कि कौन सी entries directories हैं, जिसे किसी भी recursive delete से पहले जांचना आवश्यक है। drwxr-xr-x permission bits को पढ़ना इस कॉलम के बारे में विस्तार से बताता है।

up arrow का उपयोग करके पिछली लाइन को वापस लाएं और केवल कमांड को संपादित करें, ताकि pattern बिल्कुल वैसा ही रहे। याददाश्त के आधार पर pattern को दोबारा टाइप करने से ही गलतियाँ होती हैं।

pattern से पहले -- लगाएं। यह options के अंत को चिह्नित करता है, ताकि यदि कोई filename - से शुरू हो, तो उसे flag के बजाय एक नाम के रूप में माना जाए।

यदि आप किसी script के एक हिस्से के लिए globbing को बंद करना चाहते हैं, तो set -f इसे disable कर देता है और set +f इसे वापस चालू कर देता है।

यह आदत इसलिए महत्वपूर्ण है क्योंकि rm में undo का कोई विकल्प नहीं होता। rm -rf से हटाई गई फाइलों को रिकवर करना एक धीमी प्रक्रिया है और आमतौर पर अधूरी रहती है, इसलिए पूर्वावलोकन करना किसी भी अन्य विकल्प की तुलना में बहुत कम जोखिम भरा है।

काम पूरा होने पर practice directory को साफ कर दें। पहले path को प्रिंट करें और उसे पढ़ें, क्योंकि गलत variable पर निर्देशित rm -rf वही दुर्घटना है जिसके बारे में यह section चेतावनी देता है।

cd ~
echo "$lab"
rm -rf -- "$lab"

FAQ

find . -name *.log गलत फाइलें क्यों ढूँढता है?

ऐसा इसलिए होता है क्योंकि find शुरू होने से पहले ही bash *.log को expand कर देता है। शेल वर्तमान डायरेक्टरी में पैटर्न का मिलान करता है और परिणामी फाइलनाम को find को भेज देता है, जो फिर हर गहराई पर केवल उस एक नाम को खोजता है। यदि दो या अधिक फाइलें मेल खाती हैं, तो find को अतिरिक्त तर्क (arguments) मिलते हैं जहाँ उसे एक एक्सप्रेशन की अपेक्षा होती है, और वह उपयोग त्रुटि (usage error) रिपोर्ट करता है। पैटर्न को find . -name '*.log' के रूप में कोट (quote) करें ताकि find स्वयं मिलान करे, अपने स्वयं के नियमों और अपने स्वयं के रिकर्शन के साथ।

जब मेरा पैटर्न शाब्दिक टेक्स्ट (literal text) के रूप में दिखाई देता है, तो इसका क्या अर्थ है?

इसका मतलब है कि कुछ भी मेल नहीं खाया। डिफ़ॉल्ट रूप से, bash एक बेमेल पैटर्न को वैसा ही छोड़ देता है और कच्चे कैरेक्टर्स को कमांड को पास कर देता है, जो फिर उन्हें फाइलनाम के रूप में मानता है। एक बेमेल पैटर्न को त्रुटि में बदलने के लिए shopt -s failglob सेट करें जो कमांड को रोक दे, या इसे कुछ भी न होने (expand to nothing) के लिए shopt -s nullglob सेट करें। nullglob के तहत, यह जांचें कि क्या कमांड बिना किसी तर्क के भी सही काम करती है, क्योंकि ls *.nope एक खाली ls बन जाता है और पूरी डायरेक्टरी को लिस्ट कर देता है।

मैं bash में एक पैटर्न को छोड़कर बाकी सभी फाइलों का मिलान कैसे करूँ?

shopt -s extglob के साथ विस्तारित पैटर्न (extended patterns) को सक्षम करें, फिर निषेध (negation) फॉर्म का उपयोग करें। !(*.log) उन नामों से मेल खाता है जो .log पर समाप्त नहीं होते हैं, और !(*.log|*.md) दोनों को बाहर कर देता है। छिपी हुई फाइलें परिणाम से बाहर रहती हैं जब तक कि dotglob भी सेट न हो, और डायरेक्टरी शामिल होती हैं, इसलिए rm को देने से पहले printf '%s\n' !(*.log) के साथ पैटर्न का पूर्वावलोकन करें।

* छिपी हुई फाइलों को क्यों छोड़ देता है?

शुरुआती डॉट (dot) का मिलान शाब्दिक रूप से होना चाहिए, इसलिए * कभी भी ऐसे नाम से मेल नहीं खाता जो डॉट से शुरू होता है। छिपे हुए नामों तक पहुँचने के लिए .* का उपयोग करें, या उन्हें हर सामान्य पैटर्न में शामिल करने के लिए shopt -s dotglob सेट करें। dotglob के तहत . और .. प्रविष्टियाँ हमेशा बाहर रखी जाती हैं, और bash 5.2 और बाद के संस्करण उन्हें globskipdots विकल्प के माध्यम से .* से भी बाहर रखते हैं, जो डिफ़ॉल्ट रूप से चालू रहता है।

क्या मुझे ** के काम करने के लिए globstar की आवश्यकता है?

हाँ। shopt -s globstar के बिना, bash ** को एक सामान्य * के रूप में मानता है, जो एक डायरेक्टरी के अंदर मेल खाता है और वहीं रुक जाता है। globstar चालू होने पर, एक ** जो एक पूरा पाथ कंपोनेंट बनाता है, किसी भी गहराई पर मेल खाता है, इसलिए **/*.log वर्तमान डायरेक्टरी और उसके नीचे की हर सब-डायरेक्टरी तक पहुँच जाता है, और **/ केवल डायरेक्टरी से मेल खाता है। ध्यान दें कि ** डायरेक्टरी के सिम्बॉलिक लिंक का अनुसरण नहीं करता है, इसलिए सिम्बॉलिक लिंक से बने ट्री के लिए find -L का उपयोग करें।

#bash#globbing#shell#linux#scripting