अगर BASH की सूची में एक चर मौजूद है, तो मैं कैसे जांच सकता हूं


137

मैं बैश में एक स्क्रिप्ट लिखने की कोशिश कर रहा हूं जो उपयोगकर्ता इनपुट की वैधता की जांच करता है।
मैं xमान्य मानों की सूची में इनपुट (वेरिएबल ) कहना चाहता हूं ।

मैं इस समय साथ आया हूँ:

for item in $list
do
    if [ "$x" == "$item" ]; then
        echo "In the list"
        exit
    fi
done

मेरा सवाल यह है कि क्या ऐसा करने का एक सरल तरीका है, अधिकांश प्रोग्रामिंग भाषाओं के लिए
कुछ ऐसा है list.contains(x)

जोड़:
सूची कहें:

list="11 22 33"

मेरा कोड केवल उन मूल्यों के लिए संदेश को प्रतिध्वनित करेगा listक्योंकि एक सरणी के रूप में माना जाता है और एक स्ट्रिंग नहीं है, सभी स्ट्रिंग जोड़तोड़ मान्य होंगे 1जबकि मैं चाहता हूं कि यह विफल हो जाए।

जवाबों:


142
[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'

या एक समारोह बनाएँ:

contains() {
    [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}

इसके प्रयेाग के लिए:

contains aList anItem
echo $? # 0: match, 1: failed

37
होना चाहिए[[ $list =~ (^| )$x($| ) ]] && echo 'yes' || echo 'no'
मैटेवे अक्सेनोव

12
यदि उपयोगकर्ता इनपुट में नियमित अभिव्यक्ति विशेष वर्ण हैं, तो उदाहरण के लिए गलत सकारात्मक दे सकते हैंx=.
ग्लेन जैकमैन

4
यह कोई गलत सकारात्मक / नकारात्मक नहीं देगा contains () { [[ "$1" =~ (^|[[:space:]])"$2"($|[[:space:]]) ]]; }:।
स्कोज़िन

6
अधिक रसीला समाधान [[ " $list " =~ " $x " ]] && echo 'yes' || echo 'no':। यह सही है कि अंतरिक्ष विभाजक है और $xइसमें स्थान नहीं है
तियानरेन लियू

2
मुझे लगता है कि "ए" फ़ंक्शन का उपयोग करना बेहतर है isIn()ताकि आप पहले मापदंडों में आइटम लिख सकें। इसके अलावा, आप इस तरह echoका उपयोग करने के बजाय कुछ कर सकते हैं exit: [[ $2 =~ (^|[[:space:]])$1($|[[:space:]]) ]] && echo 1 || echo 0तो आप इस तरह से फ़ंक्शन का उपयोग कर सकते हैं:result=$(isIn "-t" "-o -t 45") && echo $result
हायज

34

Matvey सही है, लेकिन आपको $ x का उद्धरण देना चाहिए और किसी भी प्रकार के "रिक्त स्थान" (उदाहरण के लिए नई लाइन) पर विचार करना चाहिए

[[ $list =~ (^|[[:space:]])"$x"($|[[:space:]]) ]] && echo 'yes' || echo 'no' 

तो, यानी

# list_include_item "10 11 12" "2"
function list_include_item {
  local list="$1"
  local item="$2"
  if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
    # yes, list include item
    result=0
  else
    result=1
  fi
  return $result
}

तब अंत

`list_include_item "10 11 12" "12"`  && echo "yes" || echo "no"

या

if `list_include_item "10 11 12" "1"` ; then
  echo "yes"
else 
  echo "no"
fi

ध्यान दें कि आप का उपयोग करना चाहिए "" चर के मामले में :

`list_include_item "$my_list" "$my_item"`  && echo "yes" || echo "no"

3
यह समाधान तब भी काम करता है, जब $itemइसमें विशेष वर्ण हों, जैसे .(लेकिन $listचर को शायद परीक्षण के अंदर उद्धृत करने की आवश्यकता है)। और फ़ंक्शन को और भी सरल परिभाषित किया जा सकता है contains () { [[ "$1" =~ (^|[[:space:]])"$2"($|[[:space:]]) ]]; }:।
skozin

जैसे मामलों में काम नहीं करता है: list="aa bb xx cc ff"औरx="aa bb"
क्रिएटिवशिप

हैलो। मैं बैशस्क्रिप्ट बुनियादी बातों को सीखने की कोशिश कर रहा हूं और मैं जानना चाहता था कि आप सूची में स्ट्रिंग की सूची को कैसे पार्स कर सकते हैं, और आप उस सूची में मौजूद चेक की जांच करते हैं। मैं आपको अंतरिक्ष का उपयोग करके विभाजित कर सकता हूं लेकिन मैं पूरी तरह से अभिव्यक्ति को समझ नहीं सका। तुम मुझे गूगल करने के लिए कीवर्ड प्रदान कर सकते हैं इस अभिव्यक्ति के मूल सिद्धांतों: $list =~ (^|[[:space:]])"$item"($|[[:space:]])। या, यदि आपके पास समय है, तो मुझे इस अभिव्यक्ति के लिए आपका स्पष्टीकरण सुनकर खुशी होगी। नोट: मुझे लगता है कि यह एक रेगेक्स एक्सप्रेशन है (^ आदि के साथ शुरू होता है) लेकिन मुझे नहीं पता कि क्या है ~ ~ का मतलब है। इसलिए मैं एक समग्र स्पष्टीकरण पसंद करूंगा: P
अली Yılmaz

28

IMHO का सबसे आसान समाधान मूल स्ट्रिंग को एक स्थान के साथ तैयार करना और जोड़ना है और एक regex के खिलाफ जांच करना है [[ ]]

haystack='foo bar'
needle='bar'

if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
    ...
fi

यह एक विकल्प के रूप में सुई युक्त मूल्यों के साथ मूल्यों पर गलत सकारात्मक नहीं होगा, उदाहरण के लिए एक धड़ के साथ foo barbaz

(यह अवधारणा बेशर्मी से चुराई हुई फॉर्म JQuery की hasClass()-Method है)


4
यदि विभाजक स्थान नहीं है, तो समाधान अधिक स्पष्ट है। यह रेगेक्स के बिना भी किया जा सकता है: haystack="foo:bar"और[[ ":$haystack:" = *:$needle:* ]]
फ़िफी

25

कैसा रहेगा

echo $list | grep -w $x

$?निर्णय लेने के लिए आप या तो आउटपुट या उपरोक्त लाइन की जांच कर सकते हैं ।

grep -w पूरे शब्द पैटर्न पर जाँच।


1
यदि यह "वैल्यू" वैध है ("सूची में") तो यह मान्य नहीं है, क्योंकि यह इसका विकल्प है
toir Farchy

हाँ, यह होगा, जैसा कि स्वीकृत उत्तर है। @glennjackman एक कार्यशील समाधान देता है।
f.ardelian

3
grep को शांत करने के लिए आप grep -q का उपयोग कर सकते हैं
अमीर

यह आंशिक मैचों को भी स्वीकार करेगा, जो कि उपयोगकर्ता को नहीं चाहिए
कार्निसर

3
@ कर्णप्रिय व्यक्ति सटीक मिलान करने के लिए बस grep -w $ x का उपयोग करें
user1297406

18

यदि आप डबल ब्रैकेट का उपयोग करते हैं, तो आप केस स्टेटमेंट के बाहर भी (* वाइल्डकार्ड) का उपयोग कर सकते हैं:

string='My string';

if [[ $string == *My* ]]
then
echo "It's there!";
fi

3
सरल और सुरुचिपूर्ण, +1
जोआ परेरा

14
यह गलत सकारात्मक देगा यदि "मेरा" एक और स्ट्रिंग का एक स्ट्रिंग है, जैसे स्ट्रिंग = 'MyCommand string'।
ल्यूक ली

यह ध्यान देने योग्य है कि वाइल्डकार्ड ( *My*) परीक्षण के दाईं ओर होना चाहिए।
याकूब वीनस

8

यदि आपके मूल्यों की सूची को स्क्रिप्ट में हार्ड-कोडित किया जाना है, तो इसका उपयोग करना परीक्षण करना काफी सरल है case। यहां एक छोटा उदाहरण दिया गया है, जिसे आप अपनी आवश्यकताओं के अनुसार अपना सकते हैं:

for item in $list
do
    case "$x" in
      item1|item2)
        echo "In the list"
        ;;
      not_an_item)
        echo "Error" >&2
        exit 1
        ;;
    esac
done

यदि सूची रनटाइम पर एक सरणी चर है, तो अन्य उत्तरों में से एक संभवतः एक बेहतर फिट है।


7

यदि सूची स्क्रिप्ट में तय की गई है, तो मुझे निम्नलिखित सबसे अच्छा लगता है:

validate() {
    grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}

validate "$x"अगर $xअनुमति है तो परीक्षण करने के लिए उपयोग करें ।

यदि आप एक-लाइनर चाहते हैं, और आइटम नामों में व्हाट्सएप की परवाह नहीं करते हैं, तो आप इसका उपयोग कर सकते हैं ( -wइसके बजाय नोटिस -x):

validate() { echo "11 22 33" | grep -F -q -w "$1"; }

टिप्पणियाँ:

  • यह POSIX shअनुपालन है।
  • validateसबस्ट्रिंग स्वीकार नहीं करता है ( -xयदि आप चाहते हैं कि grep के विकल्प को हटा दें )।
  • validateअपने तर्क को एक निश्चित स्ट्रिंग के रूप में व्याख्या करता है, न कि एक नियमित अभिव्यक्ति ( -Fयदि आप चाहते हैं तो grep के विकल्प को हटा दें )।

समारोह का अभ्यास करने के लिए नमूना कोड:

for x in "item 1" "item2" "item 3" "3" "*"; do
    echo -n "'$x' is "
    validate "$x" && echo "valid" || echo "invalid"
done

6

सहयोगी सरणियों की कुंजी का दोहन करने पर विचार करें । मैं इस outperforms दोनों regex / पैटर्न मिलान और पाशन मान लेंगे, हालांकि मैंने इसे प्रोफाइल नहीं किया है।

declare -A list=( [one]=1 [two]=two [three]='any non-empty value' )
for value in one two three four
do
    echo -n "$value is "
    # a missing key expands to the null string, 
    # and we've set each interesting key to a non-empty value
    [[ -z "${list[$value]}" ]] && echo -n '*not* '
    echo "a member of ( ${!list[*]} )"
done

आउटपुट:

one is a member of ( one two three )
two is a member of ( one two three )
three is a member of ( one two three )
four is *not* a member of ( one two three )

2
... और आप echo -nमापदंडों के रचनात्मक उपयोग के साथ उस प्रतिस्थापन को सरल बना सकते हैं (और भरोसा नहीं करते हैं ) do is="${list[$value]+is }"; echo "$value ${is:-is *not* }a member of ( ${!list[*]} )"; done:।
स्पाइट

क्या इस तरह की एक सरणी बनाने का एक आसान तरीका है अगर मेरे पास `सूची =" एक दो तीन xyz ... "जैसी एक (लंबी) सूची है?
ओटोमेटा

5

मुझे लगता है कि echo $LIST | xargs -n1 echo | grep $VALUEनीचे दिए गए रूप में फ़ॉर्म का उपयोग करना आसान है :

LIST="ITEM1 ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | xargs -n1 echo | grep -e \"^$VALUE`$\" ]; then
    ...
fi

यह एक अंतरिक्ष-पृथक सूची के लिए काम करता है, लेकिन आप इसे :निम्न करके किसी अन्य सीमांकक (जैसे ) के लिए अनुकूलित कर सकते हैं :

LIST="ITEM1:ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | sed 's|:|\\n|g' | grep -e \"^$VALUE`$\"`" ]; then
   ...
fi

ध्यान दें कि "परीक्षण के लिए काम करने के लिए आवश्यक हैं।


यह LIST="SOMEITEM1 ITEM2"सही ITEM1नहीं होने का कारण होगा, भले ही वह इसमें न हो
Ofir Farchy

अच्छी पकड़, मैंने आंशिक मैच को बाहर करने के लिए grep -e के साथ उदाहरण को अद्यतन किया।
सेबेस्टियन पियरे

मेरा मानना ​​है कि "if" स्टेटमेंट के अंत में एक अतिरिक्त `है। सही रूप है: [-n "` $ सूची गूंज | xargs -n1 गूंज | ग्रेप -e \ "^ $ मूल्य $ \"]
Elad Tabak

3

सोचा था कि सूची में अपना समाधान जोड़ दूंगा।

# Checks if element "$1" is in array "$2"
# @NOTE:
#   Be sure that array is passed in the form:
#       "${ARR[@]}"
elementIn () {
    # shopt -s nocasematch # Can be useful to disable case-matching
    local e
    for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
    return 1
}

# Usage:
list=(11 22 33)
item=22

if elementIn "$item" "${list[@]}"; then
    echo TRUE;
else
    echo FALSE
fi
# TRUE

item=44
elementIn $item "${list[@]}" && echo TRUE || echo FALSE
# FALSE

1

उदाहरण

$ in_list super test me out
NO

$ in_list "super dude" test me out
NO

$ in_list "super dude" test me "super dude"
YES

# How to use in another script
if [ $(in_list $1 OPTION1 OPTION2) == "NO" ]
then
  echo "UNKNOWN type for param 1: Should be OPTION1 or OPTION2"
  exit;
fi

सूची में

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH_FOR {ITEM1} {ITEM2} {ITEM3} ...

  e.g. 

  a b c d                    -> NO
  a b a d                    -> YES
  "test me" how "test me"    -> YES

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

if [ "$#" -eq 0 ]; then
  show_help
fi

SEARCH_FOR=$1
shift;

for ITEM in "$@"
do
  if [ "$SEARCH_FOR" == "$ITEM" ]
  then
    echo "YES"
    exit;
  fi
done

echo "NO"

1

टारगेट चर को केवल 'द्विपद' या 'प्रतिगमन' माना जा सकता है, तब निम्नलिखित कार्य करेगा:

# Check for modeling types known to this script
if [ $( echo "${TARGET}" | egrep -c "^(binomial|regression)$" ) -eq 0 ]; then
    echo "This scoring program can only handle 'binomial' and 'regression' methods now." >&2
    usage
fi

आप सूची में अधिक स्ट्रिंग्स जोड़ सकते हैं उन्हें एक के साथ अलग करके | (पाइप) चरित्र।

Egrep का उपयोग करने का लाभ, यह है कि आप आसानी से केस असंवेदनशीलता (-आई) जोड़ सकते हैं, या एक नियमित अभिव्यक्ति के साथ अधिक जटिल परिदृश्यों की जांच कर सकते हैं।


1

यह लगभग आपका मूल प्रस्ताव है लेकिन लगभग 1-लाइनर है। अन्य मान्य उत्तरों के रूप में जटिल नहीं, और बैश संस्करणों के आधार पर ऐसा नहीं हो सकता (पुराने विवादों के साथ काम कर सकता है)।

OK=0 ; MP_FLAVOURS="vanilla lemon hazelnut straciatella"
for FLAV in $MP_FLAVOURS ; do [ $FLAV == $FLAVOR ] && { OK=1 ; break; } ; done
[ $OK -eq 0 ] && { echo "$FLAVOR not a valid value ($MP_FLAVOURS)" ; exit 1 ; }

मुझे लगता है कि मेरा प्रस्ताव अभी भी सुधार किया जा सकता है, लंबाई और शैली दोनों में।


0

यदि यह बहुत लंबा नहीं है; आप बस उन्हें तार्किकता के साथ समानता के बीच तार कर सकते हैं या तुलना कर सकते हैं।

if [ $ITEM == "item1" -o $ITEM == "item2" -o $ITEM == "item3" ]; then
    echo In the list
fi 

मुझे यह सटीक समस्या थी और जबकि ऊपर बदसूरत है यह अधिक स्पष्ट है कि अन्य सामान्यीकृत समाधानों की तुलना में क्या चल रहा है।

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