आप कैसे बता सकते हैं कि एक स्ट्रिंग में POSIX श में एक और स्ट्रिंग है?


136

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

#!/usr/bin/env sh

if [ "$PWD" contains "String1" ]
then
    echo "String1 present"
elif [ "$PWD" contains "String2" ]
then
    echo "String2 present"
else
    echo "Else"
fi

2
मुझे लगता है कि यह पुराना है, लेकिन यहां आने वाले आगंतुकों के लिए ध्यान देने योग्य कुछ बातें हैं: (1) आमतौर पर पर्यावरण और शेल आंतरिक चर के लिए SNAKE_CASE चर नामों को आरक्षित करना अच्छा अभ्यास है। (२) सेटिंग CURRENT_DIRबेमानी है; आप बस उपयोग कर सकते हैं $PWD
nyuszika7h 22

जवाबों:


162

यहाँ अभी तक एक और समाधान है। यह POSIX सबस्ट्रिंग पैरामीटर विस्तार का उपयोग करता है , इसलिए यह बैश, डैश, कॉर्नशेल (ksh), Z शेल (zsh), आदि में काम करता है।

test "${string#*$word}" != "$string" && echo "$word found in $string"

कुछ उदाहरणों के साथ एक कार्यात्मक संस्करण:

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"
    if test "${string#*$substring}" != "$string"
    then
        return 0    # $substring is in $string
    else
        return 1    # $substring is not in $string
    fi
}

contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"

3
यह मेरे लिए काम नहीं करता है अगर सबस्ट्रिंग में बैकस्लैश शामिल हैं। हमेशा की तरह, substring="$( printf '%q' "$2" )"दिन बचाता है।
ईगोर टेन्सिन

यह गलत रूटिंसग से भी मेल खाता है। string = "aplha beta betaone" substring = "beta"। यह दोनों बीटा को एक dbeta से मिलाता है, जो मुझे लगता है कि गलत है।
राजीव

1
वाइल्डकार्ड का उपयोग करने के बारे में क्या ? [[ $haystack == *"My needle"* ]]
पाब्लो ए

4
क्या गलत है कि डबल-ब्रैकेट POSIX नहीं हैं, जो कि प्रश्न का आधार था, @ पाब्लो।
रोब कैनेडी

1
यह विशेष पात्रों की तरह काम नहीं करता है []। मेरा उत्तर देखें stackoverflow.com/a/54490453/712666
एलेक्स स्क्रीपनीक

85

शुद्ध POSIX खोल:

#!/bin/sh
CURRENT_DIR=`pwd`

case "$CURRENT_DIR" in
  *String1*) echo "String1 present" ;;
  *String2*) echo "String2 present" ;;
  *)         echo "else" ;;
esac

Ksh या bash जैसे विस्तारित गोले में फैंसी मिलान तंत्र हैं, लेकिन पुरानी शैली caseआश्चर्यजनक रूप से शक्तिशाली है।


40

अफसोस की बात है, मुझे इस तरह से करने के तरीके के बारे में पता नहीं है। हालाँकि, बैश का उपयोग करना (संस्करण 3.0.0 में शुरू करना, जो संभवतः आपके पास है), आप इस तरह = ~ ऑपरेटर का उपयोग कर सकते हैं:

#!/bin/bash
CURRENT_DIR=`pwd`

if [[ "$CURRENT_DIR" =~ "String1" ]]
then
 echo "String1 present"
elif [[ "$CURRENT_DIR" =~ "String2" ]]
then
 echo "String2 present"
else
 echo "Else"
fi

एक अतिरिक्त बोनस (और / या एक चेतावनी के रूप में, यदि आपके तार में कोई मज़ेदार पात्र है), = ~ यदि आप उद्धरण छोड़ते हैं तो regexes को सही ऑपरेंड के रूप में स्वीकार करता है।


3
रेगेक्स को उद्धृत न करें, या यह सामान्य रूप से काम नहीं करेगा । उदाहरण के लिए, [[ test =~ "test.*" ]]बनाम प्रयास करें [[ test =~ test.* ]]
l0b0

1
ठीक है, यह ठीक काम करेगा यदि आप एक विकल्प के लिए परीक्षण कर रहे हैं, जैसा कि मूल प्रश्न में है, लेकिन यह सही ऑपरेंड को रेगेक्स के रूप में नहीं मानेगा। मैं अपने उत्तर को और अधिक स्पष्ट करने के लिए अपडेट करूंगा।
जॉन हायलैंड

3
यह बैश है, POSIX श नहीं जैसा कि सवाल पूछता है।
रीड

28
#!/usr/bin/env sh

# Searches a subset string in a string:
# 1st arg:reference string
# 2nd arg:subset string to be matched

if echo "$1" | grep -q "$2"
then
    echo "$2 is in $1"
else 
    echo "$2 is not in $1"
fi

2
अवांछित आउटपुट से बचने के grep -q "$2"लिए बदलें grep -q "$2" > /dev/null
विक्टर सर्जेनको

15

यहाँ आपके मुद्दे के विभिन्न समाधानों की एक कड़ी है।

यह मेरा पसंदीदा है क्योंकि यह सबसे अधिक मानव पठनीय अर्थ देता है:

स्टार वाइल्डकार्ड विधि

if [[ "$string" == *"$substring"* ]]; then
    return 1
fi
return 0

इस पर shमुझे इसके साथ "अज्ञात ऑपरेंड" मिला। हालांकि बैश के साथ काम करता है।
रोकें

13
[[POSIX नहीं है
इयान

14
case $(pwd) in
  *path) echo "ends with path";;
  path*) echo "starts with path";;
  *path*) echo "contains path";;
  *) echo "this is the default";;
esac


2
test $(echo "stringcontain" "ingcon" |awk '{ print index($1, $2) }') -gt 0 && echo "String 1 contain string 2"

-> आउटपुट: स्ट्रिंग 1 में स्ट्रिंग 2 होते हैं


2

'परीक्षण' कार्यक्रम के लिए मैनपेज देखें। यदि आप किसी निर्देशिका के अस्तित्व के लिए परीक्षण कर रहे हैं तो आप सामान्य रूप से ऐसा कुछ करेंगे:

if test -d "String1"; then
  echo "String1 present"
end

यदि आप वास्तव में एक स्ट्रिंग से मेल खाने की कोशिश कर रहे हैं तो आप बैश विस्तार नियमों और वाइल्डकार्ड्स का उपयोग कर सकते हैं:

if test -d "String*"; then
  echo "A directory starting with 'String' is present"
end

यदि आपको कुछ और जटिल करने की आवश्यकता है, तो आपको expr जैसे किसी अन्य प्रोग्राम का उपयोग करने की आवश्यकता होगी।


1
आपके दूसरे उदाहरण में एक द्विअर्थी दोहरा उद्धरण (") प्रतीत होता है।
एलेक्सिस विल्के

2

विशेष मामलों में जहां आप यह जानना चाहते हैं कि कोई शब्द लंबे पाठ में समाहित है या नहीं, आप लंबे पाठ के माध्यम से एक लूप से पुनरावृति कर सकते हैं।

found=F
query_word=this
long_string="many many words in this text"
for w in $long_string; do
    if [ "$w" = "$query_word" ]; then
          found=T
          break
    fi
done

यह शुद्ध बॉर्न शेल है।


1

यदि आप एक ksh केवल विधि चाहते हैं जो "परीक्षण" के रूप में तेज़ है, तो आप कुछ ऐसा कर सकते हैं:

contains() # haystack needle
{
    haystack=${1/$2/}
    if [ ${#haystack} -ne ${#1} ] ; then
        return 1
    fi
    return 0
}

यह हिस्टैक में सुई को हटाने और फिर पुराने और नए हॉस्टैक्स की स्ट्रिंग लंबाई की तुलना करके काम करता है।


1
क्या इसका परिणाम वापस करना संभव नहीं होगा test? में के रूप में return [ ${#haystack} -eq ${#1} ]?
एलेक्सिस विल्के

हां यह सही है। मैं इसे इस तरह से छोड़ दूंगा कि आम लोगों के लिए इसे समझना आसान हो जाए। यदि आप अपने कोड में उपयोग करते हैं, तो @AlexisWilke विधि का उपयोग करें।
जोऑफटेक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.