सवाल जांचें कि बैश में सरणी खाली है या नहीं


मेरे पास एक सरणी है जो मेरी स्क्रिप्ट चलाने के रूप में विभिन्न त्रुटि संदेशों से भरा हो जाता है।

मुझे यह जांचने का एक तरीका चाहिए कि क्या यह स्क्रिप्ट के अंत में खाली नहीं है और यदि यह है तो एक विशिष्ट कार्रवाई करें।

मैंने इसे सामान्य VAR की तरह इलाज करने और इसे जांचने के लिए -z का उपयोग करने का प्रयास किया है, लेकिन ऐसा लगता है कि यह काम नहीं कर रहा है। क्या यह जांचने का कोई तरीका है कि कोई सरणी खाली है या नहीं?

धन्यवाद


82
2018-02-11 03:59


मूल




जवाब:


मान लीजिए कि आपकी सरणी है $errors, यह देखने के लिए जांचें कि तत्वों की गिनती शून्य है या नहीं।

if [ ${#errors[@]} -eq 0 ]; then
    echo "No errors, hooray"
else
    echo "Oops, something went wrong..."
fi

113
2018-02-11 04:10



कृपया ध्यान दें कि = एक स्ट्रिंग ऑपरेटर है। यह इस मामले में ठीक काम करने के लिए होता है, लेकिन मैं उचित अंकगणितीय ऑपरेटर का उपयोग करता हूं -eq इसके बजाए (बस अगर मैं स्विच करना चाहता हूं -ge या -lt, आदि।)। - musiphil
साथ काम नहीं करता है set -u: "अनबाउंड वेरिएबल" - यदि सरणी खाली है। - Igor
@ इगोर: बैश 4.4 में मेरे लिए काम करता है। set -u;  foo=();  [ ${#foo[@]} -eq 0 ] && echo empty। अगर मैं unset foo, तो यह प्रिंट करता है foo: unbound variable, लेकिन यह अलग है: मौजूदा और खाली होने के बजाय सरणी चर मौजूद नहीं है। - Peter Cordes
उपयोग करते समय बैश 3.2 (ओएसएक्स) में भी परीक्षण किया गया set -u - जब तक आप अपना चर पहले घोषित करते हैं, यह पूरी तरह से काम करता है। - zeroimpl


आप सरणी को एक साधारण चर के रूप में भी विचार कर सकते हैं। इस तरह, बस उपयोग कर रहे हैं

if [ -z "$array" ]; then
    echo "Array empty"
else
    echo "Array non empty"
fi

या दूसरी तरफ का उपयोग कर

if [ -n "$array" ]; then
    echo "Array non empty"
else
    echo "Array empty"
fi

उस समाधान के साथ समस्या यह है कि यदि एक सरणी इस तरह घोषित की जाती है: array=('' foo)। ये चेक सरणी को खाली के रूप में रिपोर्ट करेंगे, जबकि यह स्पष्ट रूप से नहीं है। (धन्यवाद @ मुसुफिल!)

का उपयोग करते हुए [ -z "$array[@]" ] स्पष्ट रूप से एक समाधान नहीं है। घुंघराले ब्रैकेट निर्दिष्ट नहीं करने की कोशिश करता है $array एक स्ट्रिंग के रूप में ([@] उस मामले में एक साधारण शाब्दिक स्ट्रिंग है) और इसलिए हमेशा झूठी के रूप में रिपोर्ट किया जाता है: "शाब्दिक स्ट्रिंग है [@] खाली? "स्पष्ट रूप से नहीं।


6
2018-06-23 10:29



[ -z "$array" ] या [ -n "$array" ] काम नहीं करता प्रयत्न array=('' foo); [ -z "$array" ] && echo empty, और यह प्रिंट करेगा empty भले ही array स्पष्ट रूप से खाली नहीं है। - musiphil
[[ -n "${array[*]}" ]] पूरे सरणी को स्ट्रिंग के रूप में इंटरपोलेट करता है, जिसे आप गैर-शून्य लंबाई के लिए जांचते हैं। यदि आप विचार करते हैं array=("" "") खाली होने के बजाय, दो खाली तत्व होने के बजाय, यह उपयोगी हो सकता है। - Peter Cordes


मैं आम तौर पर इस मामले में अंकगणितीय विस्तार का उपयोग करता हूं:

if (( ${#a[@]} )); then
    echo not empty
fi

3
2017-08-02 06:04



अच्छा और साफ! मुझें यह पसंद है। मैं यह भी ध्यान देता हूं कि यदि सरणी का पहला तत्व हमेशा अस्वीकार्य है, (( ${#a} )) (पहले तत्व की लंबाई) भी काम करेगा। हालांकि, यह असफल हो जाएगा a=(''), जहाँ तक (( ${#a[@]} )) उत्तर में दिया गया सफल होगा। - cxw


मैंने इसे चेक किया bash-4.4.0:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]} ]]; then
        echo not empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

तथा bash-4.1.5:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]:+${array[@]}} ]]; then
        echo non-empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

बाद के मामले में आपको निम्नलिखित निर्माण की आवश्यकता है:

${array[@]:+${array[@]}}

इसके लिए रिक्त या अनसेट सरणी पर असफल नहीं होना चाहिए। ऐसा है अगर आप करते हैं set -eu जैसे मैं आमतौर पर करता हूं। यह अधिक सख्त त्रुटि जांच के लिए प्रदान करता है। से दस्तावेज़:

-e

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

यह विकल्प शैल पर्यावरण और प्रत्येक सबहेल पर्यावरण पर अलग-अलग लागू होता है (कमांड निष्पादन पर्यावरण देखें), और सबहेल में सभी आदेशों को निष्पादित करने से पहले सबहेल्स से बाहर निकलने का कारण बन सकता है।

यदि किसी कंपाउंड कमांड या शैल फ़ंक्शन को किसी संदर्भ में निष्पादित किया जाता है जहां-को अनदेखा किया जा रहा है, तो कंपाउंड कमांड या फ़ंक्शन बॉडी के भीतर निष्पादित आदेशों में से कोई भी सेटिंग-सेटिंग से प्रभावित नहीं होगा, भले ही सेट हो और कमांड एक रिटर्न देता है विफलता की स्थिति। यदि एक कंपाउंड कमांड या शैल फ़ंक्शन सेट करता है -e संदर्भ में निष्पादित करते समय -e को अनदेखा किया जाता है, तो उस सेटिंग का कोई प्रभाव नहीं होगा जब तक कि कंपाउंड कमांड या फ़ंक्शन कॉल युक्त कमांड पूरा न हो जाए।

-u

पैरामीटर विस्तार करते समय त्रुटि के रूप में विशेष पैरामीटर '@' या '*' के अलावा अनसेट चर और पैरामीटर का इलाज करें। मानक त्रुटि में एक त्रुटि संदेश लिखा जाएगा, और एक गैर-इंटरैक्टिव खोल बाहर निकल जाएगा।

यदि आपको इसकी आवश्यकता नहीं है, तो छोड़ने के लिए स्वतंत्र महसूस करें :+${array[@]} अंश।

यह भी ध्यान रखें, उपयोग करना आवश्यक है [[ ऑपरेटर यहाँ, के साथ [ आपको मिला:

$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
    echo non-empty
else
    echo empty
fi

$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty

2
2017-12-04 14:58



साथ में -u आपको वास्तव में उपयोग करना चाहिए ${array[@]+"${array[@]}"} सीएफ stackoverflow.com/a/34361807/1237617 - Jakub Bochenski
@JakubBochenski आप किस संस्करण के बारे में बात कर रहे हैं? gist.github.com/x-yuri/d933972a2f1c42a49fc7999b8d5c50b9 - x-yuri
एकल ब्रैकेट उदाहरण में समस्या है @निश्चित रूप से। आप उपयोग कर सकते हैं * सरणी विस्तार की तरह [ "${array[*]}" ]क्या आप नहीं कर सकते फिर भी, [[ ठीक काम करता है। कई खाली तारों के साथ एक सरणी के लिए इन दोनों का व्यवहार थोड़ा आश्चर्यजनक है। दोनों [ ${#array[*]} ] तथा [[ "${array[@]}" ]] के लिए झूठे हैं array=() तथा array=('') लेकिन के लिए सच है array=('' '') (दो या दो से अधिक खाली तार)। यदि आप सभी को एक या अधिक खाली तारों को सच करना चाहते थे, तो आप इसका उपयोग कर सकते थे [ ${#array[@]} -gt 0 ]। यदि आप उन्हें सभी झूठे चाहते थे, तो आप शायद कर सकते थे // उन्हें बाहर। - eisd
@eisd मैं उपयोग कर सकता था [ "${array[*]}" ], लेकिन अगर मैं इस तरह की अभिव्यक्ति में भाग लेना चाहता था, तो यह समझना मेरे लिए मुश्किल होगा कि यह क्या करता है। जबसे [...] इंटरपोलेशन के परिणाम पर तारों के संदर्भ में संचालित होता है। विरोध के रूप में [[...]], जो कि इंटरपोलेटेड के बारे में पता हो सकता है। यही है, यह जान सकता है कि यह एक सरणी पारित किया गया था। [[ ${array[@]} ]] मुझे "मुझे पता है कि सरणी खाली नहीं है" के रूप में मुझे पढ़ता है [ "${array[*]}" ] जैसा कि "जांच करें कि सभी सरणी तत्वों के इंटरपोलेशन का परिणाम एक गैर-खाली स्ट्रिंग है"। - x-yuri
... दो खाली तारों के साथ व्यवहार के लिए यह मेरे लिए आश्चर्य की बात नहीं है। एक खाली स्ट्रिंग के साथ व्यवहार आश्चर्यजनक है। लेकिन तर्कसंगत रूप से उचित है। के बारे में [ ${#array[*]} ], आप शायद मतलब था [ "${array[*]}" ], क्योंकि पूर्व किसी भी तत्व के लिए सच है। क्योंकि तत्वों की संख्या हमेशा खाली नहीं होती है। उत्तरार्द्ध के बारे में दो तत्वों के साथ, ब्रैकेट के अंदर अभिव्यक्ति फैलती है ' ' जो गैर-खाली स्ट्रिंग है। से संबंधित [[ ${array[@]} ]], वे बस सोचते हैं (और सही तरीके से) कि दो तत्वों की कोई भी सरणी खाली नहीं है। - x-yuri


मेरे मामले में, दूसरा जवाब पर्याप्त नहीं था क्योंकि सफेद जगहें हो सकती थीं। मैं साथ आया था:

if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
  echo "No options"
else
  echo "Options found"
fi

0
2018-02-17 19:54



echo | wc शैल बिल्ट-इन्स का उपयोग करके तुलनात्मक रूप से अक्षम अक्षम लगता है। - Peter Cordes
सुनिश्चित नहीं है कि मैं @ पीटरकॉर्डिस समझता हूं, क्या मैं दूसरे उत्तरों को संशोधित कर सकता हूं ' [ ${#errors[@]} -eq 0 ]; व्हाइटस्पेस समस्या के आसपास काम करने के लिए एक तरह से? मैं अंतर्निहित भी पसंद करूंगा। - Micha
व्हाइटस्पेस वास्तव में समस्या का कारण बनता है? $# एक संख्या में फैलता है, और इसके बाद भी ठीक काम करता है opts+=("")। जैसे unset opts;  opts+=("");opts+=(" "); echo "${#opts[@]}" और मुझे मिलता है 2। क्या आप ऐसा कुछ उदाहरण दिखा सकते हैं जो काम नहीं करता है? - Peter Cordes
यह बहुत समय पहले है। आईआईआरसी मूल स्रोत हमेशा कम से कम मुद्रित ""। इस प्रकार, opts = "" या opts = ("") के लिए मुझे खाली न्यूलाइन या खाली स्ट्रिंग को अनदेखा करते हुए 0, 1 नहीं चाहिए। - Micha
ठीक है, तो आपको इलाज करने की ज़रूरत है opts=("") बराबर opts=()? यह एक खाली सरणी नहीं है, लेकिन आप खाली सरणी या खाली तत्व के साथ खाली जांच सकते हैं opts=("");  [[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty। ध्यान दें कि आपका वर्तमान उत्तर "विकल्प नहीं" कहता है opts=("" "-foo"), जो पूरी तरह से फर्जी है, और यह उस व्यवहार को पुन: उत्पन्न करता है। आप ऐसा कर सकते हैं [[ -z "${opts[*]}" ]] मुझे लगता है, सभी सरणी तत्वों को एक फ्लैट स्ट्रिंग में विभाजित करने के लिए, जो -z गैर-शून्य लंबाई के लिए जांच करता है।  यदि पहले तत्व की जांच करना पर्याप्त है, -z "$opts" काम करता है। - Peter Cordes


मैं डबल ब्रैकेट का उपयोग करना पसंद करता हूं:

if [[ !${array[@]} ]]
then
    echo "Array is empty"
else
    echo "Array is not empty"
fi

डबल ब्रैकेट्स: https://stackoverflow.com/questions/669452/is-preferable-over-in-bash


0
2017-11-04 06:40