यदि तत्व बैश में है तो टेस्ट करें


17

अगर किसी सरणी में बैश में तत्व होता है (तो लूपिंग से बेहतर)?

वैकल्पिक रूप से, यह जांचने का एक और तरीका है कि क्या संख्या या स्ट्रिंग पूर्वनिर्धारित स्थिरांक के किसी सेट के बराबर है?

जवाबों:


24

बैश 4 में, आप सहयोगी सरणियों का उपयोग कर सकते हैं:

# set up array of constants
declare -A array
for constant in foo bar baz
do
    array[$constant]=1
done

# test for existence
test1="bar"
test2="xyzzy"

if [[ ${array[$test1]} ]]; then echo "Exists"; fi    # Exists
if [[ ${array[$test2]} ]]; then echo "Exists"; fi    # doesn't

आरंभ में आप सेट अप करने के लिए भी सीधे कार्य कर सकते हैं:

array[foo]=1
array[bar]=1
# etc.

या इस तरह:

array=([foo]=1 [bar]=1 [baz]=1)

वास्तव में, [[]] परीक्षण उस मामले में काम नहीं करता है जब मूल्य रिक्त होता है। जैसे, "सरणी ['परीक्षण'] = ''"। इस स्थिति में, कुंजी 'परीक्षण' मौजूद है, और आप इसे $ {! सरणी [@]} के साथ सूचीबद्ध देख सकते हैं, लेकिन "[[$ {सरणी ['परीक्षण']]]; $ गूंज?" गूँज 1, न कि 0.
हरदेस

1
${array[$test1]}सरल है, लेकिन एक समस्या है: यह काम नहीं करेगा यदि आप set -uअपनी स्क्रिप्ट में उपयोग करते हैं (जो अनुशंसित है), जैसा कि आपको "अनबाउंड चर" मिलेगा।
टॉकलैंड

@ टॉकलैंड: इसकी सिफारिश कौन करता है? मैं निश्चित रूप से नहीं।
अगली सूचना तक रोक दिया गया।

@ डेनिसविलियम्सन: ठीक है, कुछ लोग इसकी सलाह देते हैं, लेकिन मुझे लगता है कि इन झंडों के मूल्य की परवाह किए बिना एक समाधान करना अच्छा होगा।
टॉकलैंड


10

यह एक पुराना प्रश्न है, लेकिन मुझे लगता है कि जो सबसे सरल उपाय है वह अभी तक सामने नहीं आया है test ${array[key]+_}:। उदाहरण:

declare -A xs=([a]=1 [b]="")
test ${xs[a]+_} && echo "a is set"
test ${xs[b]+_} && echo "b is set"
test ${xs[c]+_} && echo "c is set"

आउटपुट:

a is set
b is set

कैसे यह काम की जाँच को देखने के लिए इस


2
जानकारी पुस्तिका ने आपको envउपनाम, प्रोज और अन्य कार्यों में अस्पष्टता से बचने के लिए उपयोग करने की सिफारिश की है, जिन्होंने "परीक्षण" नाम को अपनाया हो सकता है। जैसा ऊपर है env test ${xs[a]+_} && echo "a is set"। आप डबल-ब्रैकेट का उपयोग करके भी यह कार्यक्षमता प्राप्त कर सकते हैं, एक ही चाल फिर अशक्त के लिए जाँच:[[ ! -z "${xs[b]+_}" ]] && echo "b is set"
A.Danischewski

इसके अलावा, आप भी सरल उपयोग कर सकते हैं[[ ${xs[b]+set} ]]
Arne L.

5

यह जांचने का एक तरीका है कि क्या एक साहचर्य सरणी का एक तत्व मौजूद है (सेट नहीं है), यह खाली से अलग है:

isNotSet() {
    if [[ ! ${!1} && ${!1-_} ]]
    then
        return 1
    fi
}

फिर इसका उपयोग करें:

declare -A assoc
KEY="key"
isNotSet assoc[${KEY}]
if [ $? -ne 0 ]
then
  echo "${KEY} is not set."
fi

बस एक ध्यान दें: घोषित -एक करता बैश 3.2.39 (Debian लेनी) पर काम नहीं है, लेकिन यह पार्टी 4.1.5 (Debian निचोड़) पर काम करता है
पावेल Polewicz

साहचर्य सरणियों बैश 4 में शुरू किए गए थे
डिएगो एफ ड्युरान

1
ध्यान दें कि if ! some_check then return 1= some_check। तो: isNotSet() { [[ ... ]] }। नीचे मेरे समाधान की जांच करें, आप इसे एक साधारण जांच में कर सकते हैं।
टॉकलैंड

3

आप देख सकते हैं कि ऐरे की सामग्री को grep में दर्ज करके कोई प्रविष्टि मौजूद है या नहीं।

 printf "%s\n" "${mydata[@]}" | grep "^${val}$"

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

# given the following data
mydata=(a b c "hello world")

for val in a c hello "hello world"
do
           # get line # of 1st matching entry
    ix=$( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 )

    if [[ -z $ix ]]
    then
        echo $val missing
    else
         # subtract 1.  Bash arrays are zero-based, but grep -n returns 1 for 1st line, not 0 
        echo $val found at $(( ix-1 ))
    fi
done

a found at 0
c found at 2
hello missing
hello world found at 3

स्पष्टीकरण:

  • $( ... ) एक चर में एक कमांड के उत्पादन पर कब्जा करने के लिए backticks का उपयोग करने के समान है
  • printf प्रति पंक्ति एक तत्व mydata को आउटपुट करता है
  • (आवश्यक सभी उद्धरण, के साथ साथ @के बजाय *. 2 लाइनों में इस टाल बंटवारे "हैलो दुनिया")
  • grepसटीक स्ट्रिंग की खोज: ^और $लाइन की शुरुआत और अंत से मेल खाते हैं
  • grep -n रिटर्न लाइन #, 4 के रूप में: हैलो दुनिया
  • grep -m 1 केवल पहला मैच पाता है
  • cut सिर्फ लाइन नंबर निकालता है
  • लौटी रेखा संख्या से 1 घटाएं।

आप निश्चित रूप से घटाव को कमांड में मोड़ सकते हैं। लेकिन फिर लापता के लिए -1 का परीक्षण करें:

ix=$(( $( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 ) - 1 ))

if [[ $ix == -1 ]]; then echo missing; else ... fi
  • $(( ... )) पूर्णांक अंकगणित करता है

1

मुझे नहीं लगता कि आप इसे ठीक से लूपिंग के बिना कर सकते हैं जब तक कि आपके पास सरणी में बहुत सीमित डेटा न हो ।

यहां एक सरल संस्करण है, यह सही ढंग से कहेगा कि "Super User"सरणी में मौजूद है। लेकिन यह भी कहा जाएगा कि "uper Use"यह सरणी में है।

MyArray=('Super User' 'Stack Overflow' 'Server Fault' 'Jeff' );
FINDME="Super User"

FOUND=`echo ${MyArray[*]} | grep "$FINDME"`

if [ "${FOUND}" != "" ]; then
  echo Array contains: $FINDME
else
  echo $FINDME not found
fi

#
# If you where to add anchors < and > to the data it could work
# This would find "Super User" but not "uper Use"
#

MyArray2=('<Super User>' '<Stack Overflow>' '<Server Fault>' '<Jeff>' );

FOUND=`echo ${MyArray2[*]} | grep "<$FINDME>"`

if [ "${FOUND}" != "" ]; then
  echo Array contains: $FINDME
else
  echo $FINDME not found
fi

समस्या यह है कि एंकर को जोड़ने का कोई आसान तरीका नहीं है (जो मैं सोच सकता हूं) सरणी के माध्यम से लूप करने के अलावा। जब तक आप उन्हें सरणी में डालने से पहले जोड़ सकते हैं ...


यह एक अच्छा समाधान है जब स्थिरांक अल्फ़ान्यूमेरिक होते हैं, हालांकि (साथ grep "\b$FINDME\b")। संभवतः गैर-अल्फ़ान्यूमेरिक स्थिरांक के साथ काम कर सकता है, जिसमें कोई रिक्त स्थान नहीं है, "(^| )$FINDME(\$| )"(या ऐसा कुछ ... मैं कभी भी यह जानने में सक्षम नहीं हुआ कि regexp grep का क्या स्वाद उपयोग करता है।)
Tgr

1
#!/bin/bash
function in_array {
  ARRAY=$2
  for e in ${ARRAY[*]}
  do
    if [[ "$e" == "$1" ]]
    then
      return 0
    fi
  done
  return 1
}

my_array=(Drupal Wordpress Joomla)
if in_array "Drupal" "${my_array[*]}"
  then
    echo "Found"
  else
    echo "Not found"
fi

1
क्या आप इस बारे में विस्तार से बता सकते हैं कि आप इस दृष्टिकोण का सुझाव क्यों दे रहे हैं? ओपी ने पूछा कि क्या एरे के माध्यम से लूपिंग के बिना ऐसा करने का कोई तरीका है , जो आप कर रहे हैं in_array। चीयर्स
बर्टिब

खैर, कम से कम उस लूप को एक फ़ंक्शन में कैपिटल किया जाता है, जो कई मामलों (छोटे डेटा सेट के साथ) के लिए पर्याप्त हो सकता है, और इसे 4+ बैश की आवश्यकता नहीं है। शायद ${ARRAY[@]}इस्तेमाल किया जाना चाहिए।
टोबियास
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.