जांचें कि क्या कोई स्ट्रिंग बैश स्क्रिप्ट में एक रेगेक्स से मेल खाती है


204

मेरी स्क्रिप्ट को प्राप्त होने वाले तर्कों में से एक निम्न प्रारूप में एक तारीख है yyyymmdd:।

मैं जांचना चाहता हूं कि क्या मुझे इनपुट के रूप में एक वैध तारीख मिलती है।

मैं यह कैसे कर सकता हूँ? मैं जैसे रेगीक्स का उपयोग करने की कोशिश कर रहा हूं:[0-9]\{\8}


यह देखना कि प्रारूप सही है या नहीं। लेकिन मुझे नहीं लगता कि आप बिल (बिल्ट-इन के साथ) में यह देख सकते हैं कि तारीख वैध है या नहीं।
RedX

जवाबों:


316

यदि आप एक स्ट्रिंग रेगेक्स पैटर्न से मेल खाते हैं, तो यह जांचने के लिए [[ ]]कि आप रेगुलर एक्सप्रेशन मैच ऑपरेटर के साथ टेस्ट कंस्ट्रक्शन का उपयोग कर सकते हैं =~

अपने विशिष्ट मामले के लिए, आप लिख सकते हैं:

[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"

या अधिक सटीक परीक्षण:

[[ $date =~ ^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$ ]] && echo "yes"
#           |^^^^^^^^ ^^^^^^ ^^^^^^  ^^^^^^ ^^^^^^^^^^ ^^^^^^ |
#           |   |     ^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^ |
#           |   |          |                   |              |
#           |   |           \                  |              |
#           | --year--   --month--           --day--          |
#           |          either 01...09      either 01..09     end of line
# start of line            or 10,11,12         or 10..29
#                                              or 30, 31

यही है, आप बैश में एक regex को परिभाषित कर सकते हैं जो आपके इच्छित प्रारूप से मेल खाता है। इस तरह से आप कर सकते हैं:

[[ $date =~ ^regex$ ]] && echo "matched" || echo "did not match"

जहां आदेशों के बाद &&क्रियान्वित कर रहे हैं अगर परीक्षण सफल होता है, और आदेश के बाद ||यदि परीक्षण असफल होने पर क्रियान्वित कर रहे हैं।

ध्यान दें कि यह बैश में यूजर इनपुट डेट फॉर्मेट वेरिफिकेशन में एलेक्स-डैनियल जैकीमेंको द्वारा समाधान पर आधारित है ।


अन्य गोले में आप ग्रीप का उपयोग कर सकते हैं । यदि आपका शेल POSIX अनुपालन है, तो करें

(echo "$date" | grep -Eq  ^regex$) && echo "matched" || echo "did not match"

में मछली है, जो POSIX अनुरूप नहीं है, आप कर सकते हैं

echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"

19
मुझे इसकी जानकारी है, लेकिन मैं यह भी ध्यान रखना पसंद करता हूं कि कौन पूछ रहा है और वे कितनी दूर हैं। यदि हम बहुत जटिल परिस्थितियाँ प्रदान करते हैं, तो वे कुछ भी नहीं सीखेंगे और जब भी उन्हें कोई और संदेह होगा, बस वापस आएँगे। मैं अधिक आत्म-समझने योग्य उत्तर देना पसंद करता हूं।
फेडोरक्वी 'एसओ

7
हे। वैसे, सीखने का एकमात्र तरीका बहुत सारे अच्छे कोड पढ़ना है। यदि आप गलत कोड देते हैं जो समझने में आसान है, लेकिन उपयोग करने की अनुशंसा नहीं की जाती है - तो यह सिखाने का एक बुरा तरीका है। इसके अलावा, मुझे पूरा यकीन है कि जिन लोगों ने बस बैश सीखना शुरू कर दिया है (शायद पहले से ही किसी अन्य भाषा के कुछ बिट्स को जानना) वे फ्लैग के grepसाथ कुछ कमांड की तुलना में रेक्स के लिए बैश सिंटैक्स को अधिक आसानी से समझ पाएंगे -E
एलेक्स-डैनियल जकिमेंको-ए।

8
@ एलेक्स-डैनियलजैकिमेंको मैं फिर से इस पद से गुजरा और अब मैं मानता हूं कि बैश रेगेक्स का उपयोग करना सबसे अच्छा है। अच्छी दिशा, अद्यतन उत्तर में इंगित करने के लिए धन्यवाद।
फेडोरक्वी 'एसओ ने' सेप

4
अपवोट, जो इसे ओपी प्रश्न से थोड़ा परे उपयोग करने की अनुमति देता है, उदाहरण के लिए, ..
डेरेकसन

3
@ अगर आप उपयोग कर रहे हैं sh, fishया अन्य कम सुसज्जित गोले में grep का उपयोग कर एलेक्सा-डैनियलजेकिमको सबसे अच्छा विकल्प लगता है ।
टोमेक्वी

47

बैश संस्करण 3 में आप '= ~' ऑपरेटर का उपयोग कर सकते हैं:

if [[ "$date" =~ ^[0-9]{8}$ ]]; then
    echo "Valid date"
else
    echo "Invalid date"
fi

संदर्भ: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF

नोट: डबल ब्रैकेट के भीतर मिलान ऑपरेटर में उद्धृत, [[]], अब बैश संस्करण ३.२ के रूप में आवश्यक नहीं है


20
आपको नियमित एक्सप्रेशन में चार का उपयोग नहीं करना चाहिए? क्योंकि जब मैं एक्सप्रेशन का उपयोग करता हूं तो यह काम नहीं करता है
Dawid Drozd

इसके अलावा, {और} का बैकस्लैश बचना भी इसी तरह की समस्या है।
15

32

यह जांचने का एक अच्छा तरीका है कि क्या स्ट्रिंग सही तिथि है, कमांड तिथि का उपयोग करना है:

if date -d "${DATE}" >/dev/null 2>&1
then
  # do what you need to do with your date
else
  echo "${DATE} incorrect date" >&2
  exit 1
fi

टिप्पणी से: कोई स्वरूपण का उपयोग कर सकता है

if [ "2017-01-14" == $(date -d "2017-01-14" '+%Y-%m-%d') ] 

9
अपने उत्तर को अत्यधिक रेट करें क्योंकि यह तारीखों को तारीखों से निपटने की अनुमति देता है न कि त्रुटि-प्रवण प्रतिक्षेपों की
अली

यह व्यापक तारीख विकल्पों पर जाँच के लिए अच्छा है, लेकिन अगर आपको किसी विशिष्ट तिथि प्रारूप को सत्यापित करने की आवश्यकता है, तो क्या वह ऐसा कर सकता है? उदाहरण के लिए अगर मैं date -d 2017-11-14eइसे Tue Nov 14 05:00:00 UTC 2017 लौटाता हूं, लेकिन यह मेरी स्क्रिप्ट को तोड़ देगा।
योशिय्याह

1
आप कुछ इस तरह का उपयोग कर सकते हैं: अगर ["2017-01-14" == $ (दिनांक -d "2017-01-14" '+% Y-% m-% d')] यह परीक्षण करता है कि क्या तिथि सही है और जांचें कि क्या परिणाम आपके दर्ज किए गए डेटा के समान है। वैसे, स्थानीय तारीख के प्रारूप (उदाहरण के लिए माह-दिवस-वर्ष-दिन-महीना-वर्ष) के साथ बहुत सावधान रहें
Django Janny

1
आपके स्थान के आधार पर काम नहीं हो सकता है। MM-DD-YYYY का उपयोग करके अमेरिकी स्वरूपित तिथियां दुनिया में कहीं और काम नहीं करेंगी, DD-MM-YYYY (यूरोप) या YYYY-MM-DD (एशिया के कुछ स्थान) का उपयोग करके
पॉल

@Paul, क्या काम नहीं कर सकता है? जैसा कि एक टिप्पणी में लिखा गया है, एक प्रारूपण विकल्पों का उपयोग कर सकता है ...
बेटलिस्टा

4

मैं expr matchइसके बजाय प्रयोग करेंगे =~:

expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes

यह वर्तमान में स्वीकार किए गए उत्तर का उपयोग करने से बेहतर है =~क्योंकि =~यह खाली तारों से भी मेल खाएगा, जिन्हें IMHO नहीं होना चाहिए। मान लें कि badvarपरिभाषित नहीं है, तो [[ "1234" =~ "$badvar" ]]; echo $?(गलत तरीके से) देता है 0, जबकि expr match "1234" "$badvar" >/dev/null ; echo $?सही परिणाम देता है 1

हम उपयोग करने के लिए >/dev/nullछिपाने के लिए expr matchके उत्पादन मूल्य , जो वर्णों की संख्या का मिलान नहीं हुआ है या 0 यदि कोई मिलान नहीं मिले। ध्यान दें कि इसका आउटपुट मूल्य इसकी निकास स्थिति से अलग है । बाहर निकलने की स्थिति 0 है यदि कोई मैच मिला है, या 1 अन्यथा।

आमतौर पर, इसके लिए वाक्य रचना exprहै:

expr match "$string" "$lead"

या:

expr "$string" : "$lead"

जहाँ $leadएक नियमित अभिव्यक्ति है। इसका exit statusसच (0) होगा यदि leadप्रमुख स्लाइस से मेल खाता है string(क्या इसके लिए कोई नाम है?)। उदाहरण के लिए expr match "abcdefghi" "abc"बाहर निकलता है true, लेकिन expr match "abcdefghi" "bcd"बाहर निकलता है false। (इसे इंगित करने के लिए @Carlo Wood को श्रेय


7
=~खाली स्ट्रिंग से मेल नहीं खा रहा है, आप अपने द्वारा दिए गए उदाहरण में एक खाली पैटर्न के खिलाफ स्ट्रिंग का मिलान कर रहे हैं। वाक्यविन्यास है string =~ pattern, और एक खाली पैटर्न सब कुछ से मेल खाता है।
bstpierre

2
यह एक विकल्प से मेल नहीं खाता है, यह रिटर्न (स्टडआउट) के लिए अग्रणी पात्रों की संख्या से मेल खाता है और बाहर निकलने की स्थिति सही है अगर कम से कम 1 वर्ण मिलान किया गया था। यही कारण है कि एक खाली स्ट्रिंग (जो 0 वर्णों से मेल खाती है) की झूठी स्थिति से बाहर निकलने की स्थिति है। उदाहरण के लिए expr match "abcdefghi" "^" && echo Matched || echo No match- और expr match "abcdefghi" "bcd" && echo Matched || echo No match- दोनों वापस लौटते हैं "0\nNo match"। जहां मिलान के रूप में "a.*f"वापस आ जाएगी "6\nMatched"। आपके उदाहरण में '^' का उपयोग इसलिए भी अनावश्यक है और पहले से ही निहित है।
कार्लो वुड

@bstpierre: यहां बात यह नहीं है कि कोई =~खाली तारों के मिलान के व्यवहार को तर्कसंगत बना सकता है या नहीं । यह है कि यह व्यवहार अप्रत्याशित हो सकता है और त्रुटियों का कारण हो सकता है। मैंने यह उत्तर विशेष रूप से लिखा था क्योंकि मैं इससे जल गया था।
पेंघे गेंग

@PengheGeng अप्रत्याशित व्यवहार? यदि किसी पैटर्न की कोई परिभाषा या बाधा नहीं है, तो यह वास्तव में कुछ भी मेल खाता है। एक पैटर्न की अनुपस्थिति सब कुछ के लिए एक मैच है। मजबूत कोड लिखना एक खराब स्पष्टीकरण को सही नहीं ठहराते हुए उत्तर है।
एंथोनी रटलेज

@AnthonyRutledge "मजबूत कोड" आकस्मिक कोडिंग त्रुटियों को रोकने के लिए उपलब्ध उपकरणों के सर्वोत्तम उपयोग की मांग करता है। शेल कोड में जहां एक खाली चर आसानी से और गलती से किसी भी तरह से गलत वर्तनी के रूप में पेश किया जा सकता है, मुझे नहीं लगता कि खाली चर को मिलान करने की अनुमति देना एक मजबूत विशेषता है। जाहिरा तौर पर जीएनयू का लेखक exprमुझसे सहमत है।
पेंघ गेंग

0

जहाँ किसी दिनांक का वर्ण क्रम सही है, यह निर्धारित करने के लिए regex का उपयोग सहायक हो सकता है, तो यह निर्धारित करने के लिए आसानी से उपयोग नहीं किया जा सकता है कि क्या दिनांक मान्य है। निम्नलिखित उदाहरण नियमित अभिव्यक्ति को पारित करेंगे, लेकिन सभी अमान्य तिथियां हैं: 20180231, 20190229, 20190431

इसलिए यदि आप मान्य करना चाहते हैं यदि आपका दिनांक स्ट्रिंग (इसे कॉल करें datestr) सही प्रारूप में है, तो इसे इसके साथ पार्स करना dateऔर dateस्ट्रिंग को सही प्रारूप में बदलने के लिए कहना सबसे अच्छा है । यदि दोनों तार समान हैं, तो आपके पास एक मान्य प्रारूप और वैध तिथि है।

if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
     echo "Valid date"
else
     echo "Invalid date"
fi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.