यदि फ़ाइल नाम शेल ग्लोब पैटर्न से मेल खाता है, तो मैं प्रोग्रामेटिकली कैसे बता सकता हूं?


13

मैं बताना चाहूंगा कि क्या एक स्ट्रिंग $stringएक ग्लोब पैटर्न द्वारा मिलान किया जाएगा $pattern$stringकिसी मौजूदा फ़ाइल का नाम हो सकता है या नहीं। मैं यह कैसे कर सकता हूँ?

मेरे इनपुट स्ट्रिंग्स के लिए निम्न स्वरूपों को मानें:

string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"

मैं एक पार्टी मुहावरा निर्धारित करता है कि अगर प्राप्त करना चाहते हैं $stringसे मिलान किया जाएगा $pattern1, $pattern2या किसी भी अन्य मनमाना ग्लोब पैटर्न। यहाँ मैंने अभी तक कोशिश की है:

  1. [[ "$string" = $pattern ]]

    यह लगभग काम करता है, सिवाय इसके कि $patternएक स्ट्रिंग पैटर्न के रूप में व्याख्या की जाती है और एक ग्लोब पैटर्न के रूप में नहीं।

  2. [ "$string" = $pattern ]

    इस दृष्टिकोण के साथ समस्या यह है कि $patternविस्तार किया जाता है और फिर स्ट्रिंग तुलना $stringऔर विस्तार के बीच प्रदर्शन किया जाता है $pattern

  3. [[ "$(find $pattern -print0 -maxdepth 0 2>/dev/null)" =~ "$string" ]]

    यह काम करता है, लेकिन केवल अगर $stringकोई फ़ाइल मौजूद है जो मौजूद है।

  4. [[ $string =~ $pattern ]]

    यह काम नहीं करता है क्योंकि =~ऑपरेटर $patternको एक विस्तारित नियमित अभिव्यक्ति के रूप में व्याख्या करने का कारण बनता है, न कि एक ग्लोब या वाइल्डकार्ड पैटर्न।


2
आप जिस मुद्दे को चलाने जा रहे हैं, वह {bar,baz}पैटर्न नहीं है। यह पैरामीटर विस्तार है। उस में सूक्ष्म लेकिन महत्वपूर्ण अंतर {bar,baz}कई तर्कों में बहुत जल्दी विस्तारित होता है, barऔर baz
पैट्रिक

यदि शेल मापदंडों का विस्तार कर सकता है, तो निश्चित रूप से यह बता सकता है कि क्या एक स्ट्रिंग एक ग्लोब का संभावित विस्तार है।
जयहिन्द्रन

इसे ls /foo/*
आज़माइए

1
@ पाट्रिक: बैश मैन पेज के माध्यम से पढ़ने के बाद, मैंने सीखा है कि पथनाम विस्तार के foo/{bar,baz}दौरान वास्तव में एक ब्रेस विस्तार (पैरामीटर विस्तार नहीं) foo/*है। $stringपैरामीटर विस्तार है। ये सभी अलग-अलग समय पर और विभिन्न तंत्रों द्वारा किए जाते हैं।
जयहिन्द्रन

@jayhendren @Patrick सही है, और फिर आपने सीखा कि आपका प्रश्न अंततः ऐसा नहीं है जो शीर्षक किसी को विश्वास में लेता है। बल्कि, आप विभिन्न प्रकार के पैटर्न के खिलाफ एक स्ट्रिंग से मेल खाना चाहते हैं। यदि आप एक ग्लोब पैटर्न बनाम कड़ाई से मेल खाना चाहते हैं, तो caseस्टेटमेंट बैश मैनुअल के अनुसार Pathname Expansion ("ग्लोबिंग") करता है।
माइक एस

जवाबों:


8

इस समस्या का कोई सामान्य समाधान नहीं है। इसका कारण यह है कि, बैश में, ब्रेस विस्तार (यानी, {pattern1,pattern2,...}और फ़ाइल नाम विस्तार (उर्फ ग्लोब पैटर्न) को अलग-अलग चीजों और अलग-अलग परिस्थितियों में और अलग-अलग समय पर विस्तारित माना जाता है। यहां विस्तार की पूरी सूची है जो बैश करता है:

  • ब्रेस विस्तार
  • टिल्ड का विस्तार
  • पैरामीटर और चर विस्तार
  • कमांड प्रतिस्थापन
  • अंकगणित का विस्तार
  • शब्द विभाजन
  • पथनाम विस्तार

चूंकि हम केवल इन (शायद ब्रेस, टिल्ड, और पाथनेम विस्तार) के सबसेट के बारे में परवाह करते हैं, इसलिए एक नियंत्रणीय फैशन में विस्तार को प्रतिबंधित करने के लिए कुछ पैटर्न और तंत्र का उपयोग करना संभव है। उदाहरण के लिए:

#!/bin/bash
set -f

string=/foo/bar

for pattern in /foo/{*,foo*,bar*,**,**/*}; do
    [[ $string == $pattern ]] && echo "$pattern matches $string"
done

इस स्क्रिप्ट को चलाने से निम्न आउटपुट उत्पन्न होते हैं:

/foo/* matches /foo/bar
/foo/bar* matches /foo/bar
/foo/** matches /foo/bar

यह काम करता है क्योंकि set -fpathname विस्तार को अक्षम करता है, इसलिए केवल ब्रेस एक्सपेंशन और tilde विस्तार स्टेटमेंट में होता है for pattern in /foo/{*,foo*,bar*,**,**/*}। हम [[ $string == $pattern ]]ब्रेस विस्तार के बाद पहले से प्रदर्शन किए जाने के बाद पैथनेम विस्तार के खिलाफ परीक्षण करने के लिए परीक्षण ऑपरेशन का उपयोग कर सकते हैं ।


7

मैं नहीं लगता है कि {bar,baz} है एक खोल ग्लोब पैटर्न (हालांकि निश्चित रूप से /foo/ba[rz]है) , लेकिन अगर आप जानना चाहते हैं कि चाहते $stringमैचों $patternआप कर सकते हैं:

case "$string" in 
($pattern) put your successful execution statement here;;
(*)        this is where your failure case should be   ;;
esac

आप जितना चाहें उतना कर सकते हैं:

case "$string" in
($pattern1) do something;;
($pattern2) do differently;;
(*)         still no match;;
esac

1
हाय @mikeserv, जैसा कि टिप्पणियों में दिया गया है और उत्तर जो मैंने ऊपर प्रदान किया है, मैंने पहले ही सीखा है कि आप जो कहते हैं वह सच है - {bar,baz}एक ग्लोब पैटर्न नहीं है। मैं अपने प्रश्न का हल पहले ही ले चुका हूं जो इसे ध्यान में रखता है।
jayhendren

3
+1 यह सवाल ठीक उसी तरह है जैसे शीर्षक में दिया गया है, और पहला वाक्य। हालाँकि यह प्रश्न बाद में शेल ग्लोब पैटर्न के साथ अन्य पैटर्न को बताता है।
माइक एस

3

जैसा कि पैट्रिक ने बताया कि आपको पैटर्न के "अलग प्रकार" की आवश्यकता है:

[[ /foo/bar == /foo/@(bar|baz) ]]


string="/foo/bar"
pattern="/foo/@(bar|baz)"
[[ $string == $pattern ]]

वहां उद्धरण आवश्यक नहीं हैं।


ठीक है, यह काम करता है, लेकिन सख्ती से बोलना, यह मेरे सवाल का जवाब नहीं देता है। उदाहरण के लिए, मैं उन पैटर्न पर विचार करना चाहूंगा, जो दूसरे स्रोत से आ रहे हैं, यानी पैटर्न मेरे नियंत्रण से बाहर हैं।
20

@ संजय्रेन तब आपको संभवतः आने वाले पैटर्न को उन बैश स्वीकारों में बदलना होगा।
हौक लैजिंग

तो आपके द्वारा वास्तव में किया गया मेरा प्रश्न "मैं कैसे बताऊं कि क्या एक फ़ाइल नाम एक अभिव्यक्ति का संभावित विस्तार है" से "मैं कैसे सामान्य बैश-शैली फ़ाइल नाम पैटर्न को बैश-शैली विस्तारित ग्लोब पैटर्न में परिवर्तित करता हूं।"
21 अक्टूबर को jayhendren

@jayhendren यह मानते हुए कि आप जो चाहते हैं वह असंभव लगता है "आपने जो वास्तव में किया है" वह मुझे थोड़ा अजीब लगता है लेकिन शायद यह सिर्फ एक विदेशी भाषा है। यदि आप इस नए प्रश्न को पूछना चाहते हैं तो आपको यह बताना होगा कि इनपुट पैटर्न क्या दिखते हैं। शायद यह एक साधारण sedऑपरेशन है।
हौके लैजिंग

1
@ हॉकिंग सही है। यहां आने वाले लोग यह पता लगाने के लिए कि ग्लॉब पैटर्न (उर्फ "पाथनाम एक्सपेंशन") से कैसे मेल खाते हैं, भ्रमित होने के लिए उत्तरदायी हैं, जैसा कि मैंने किया, क्योंकि शीर्षक "शेल ग्लोब पैटर्न" कहता है, लेकिन उनके प्रश्न की सामग्री एक गैर-ग्लोब पैटर्न का उपयोग करती है। । कुछ बिंदु पर, जेहेनड्रेन ने अंतर के बारे में सीखा, लेकिन उनकी प्रारंभिक भ्रम की वजह से हॉक ने उनके द्वारा किए गए तरीके का जवाब दिया।
माइक एस

1

मैं इस प्रकार grep का उपयोग करूंगा:

#!/bin/bash
string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"

if echo $string | grep -e "$pattern1" > /dev/null; then
    echo $string matches $pattern1
fi

if echo $string | grep -e "$pattern2" > /dev/null; then
    echo $string matches $pattern2
fi

जो आउटपुट देता है:

./test2.bsh 
/foo/bar matches /foo/*

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.