संज्ञा शेल विकल्प के साथ संस्करण 4.2 से पहले बैश में एक चर को कैसे परिभाषित किया जाए तो परीक्षण कैसे करें?


16

"GNU बैश, संस्करण 4.2" से पहले बैश संस्करणों -vके लिए testकमांड के विकल्प के लिए कोई समकक्ष विकल्प हैं ? उदाहरण के लिए:

shopt -os nounset
test -v foobar && echo foo || echo bar
# Output: bar
foobar=
test -v foobar && echo foo || echo bar
# Output: foo

-vएक विकल्प नहीं है test, लेकिन सशर्त अभिव्यक्तियों के लिए एक ऑपरेटर है।
टिम

@ यह एक टोकन, एक स्ट्रिंग और एक लाइन का हिस्सा होने के साथ तीन चीजें हैं: एक optionकमांड test -v, एक operatorसे एक conditional expressionऔर एक के unary test primaryलिए [ ]। शेल परिभाषाओं के साथ अंग्रेजी भाषा का मिश्रण न करें।

जवाबों:


36

सभी POSIX गोले के लिए पोर्टेबल:

if [ -n "${foobar+1}" ]; then
  echo "foobar is defined"
else
  echo "foobar is not defined"
fi

यह सुनिश्चित करें कि ${foobar:+1}यदि आप foobarउसी तरह से व्यवहार करना चाहते हैं चाहे वह खाली हो या परिभाषित नहीं हो। अपरिभाषित ${foobar-}होने पर आप एक रिक्त स्ट्रिंग प्राप्त करने के लिए उपयोग कर सकते हैं foobarऔर foobarअन्यथा के मूल्य (या उसके बाद कोई अन्य डिफ़ॉल्ट मान डाल सकते हैं -)।

Ksh में, यदि foobarघोषित किया गया है, लेकिन परिभाषित नहीं है, जैसा कि है typeset -a foobar, तो ${foobar+1}खाली स्ट्रिंग में फैलता है।

Zsh में वैरिएबल नहीं हैं जो घोषित हैं, लेकिन सेट नहीं हैं: typeset -a foobarएक खाली सरणी बनाता है।

बैश में, सरणियाँ एक अलग और आश्चर्यजनक तरीके से व्यवहार करती हैं। ${a+1}केवल 1अगर aएक गैर-खाली सरणी है, उदाहरण के लिए

typeset -a a; echo ${a+1}    # prints nothing
e=(); echo ${e+1}            # prints nothing!
f=(''); echo ${f+1}          # prints 1

एक ही सिद्धांत साहचर्य सरणियों पर लागू होता है: सरणी चर को परिभाषित किया जाता है यदि उनके पास सूचकांकों का एक गैर-खाली सेट है।

परीक्षण का एक अलग, बाश-विशिष्ट तरीका है कि क्या किसी भी प्रकार के एक चर को परिभाषित किया गया है, यह जांचने के लिए है कि क्या यह सूचीबद्ध है । यह खाली सरणियों को परिभाषित करता है, इसके विपरीत , लेकिन घोषित-लेकिन-अप्रमाणित चर ( ) को अपरिभाषित के रूप में रिपोर्ट करता है।${!PREFIX*}${foobar+1}unset foobar; typeset -a foobar

case " ${!foobar*} " in
  *" foobar "*) echo "foobar is defined";;
  *) echo "foobar is not defined";;
esac

इस के बराबर है की वापसी मूल्य का परीक्षण typeset -p foobarयाdeclare -p foobar , सिवाय इसके कि typeset -p foobarघोषित बल्कि असाइन नहीं किए गए चर पर विफल रहता है।

बश में, ksh की तरह, set -o nounset; typeset -a foobar; echo $foobarअपरिभाषित चर का विस्तार करने के प्रयास में एक त्रुटि को ट्रिगर करता है foobar। Ksh के विपरीत, set -o nounset; foobar=(); echo $foobar(या echo "${foobar[@]}") भी एक त्रुटि को ट्रिगर करता है।

ध्यान दें कि यहां वर्णित सभी स्थितियों में, ${foobar+1}खाली स्ट्रिंग का विस्तार होता है यदि और केवल तभी यदि $foobarकोई त्रुटि होती है set -o nounset


1
सरणियों के बारे में क्या? बैश संस्करण "GNU बैश, संस्करण 4.1.10 (4) -release (i686-pc-cygwin)" echo "${foobar:+1}"प्रिंट नहीं करता है 1यदि declare -a foobarपहले जारी किया गया था और इस प्रकार foobarएक अनुक्रमित सरणी है। declare -p foobarसही ढंग से रिपोर्ट declare -a foobar='()'। क्या "${foobar:+1}"केवल गैर-सरणी चर के लिए काम करता है ?
टिम फ्रिसके

@TimFriske ${foobar+1}(बिना :, मैंने अपने मूल उत्तर में दो उदाहरणों को उल्टा कर दिया है) यदि आपकी परिभाषा "परिभाषित" के $foobarतहत काम करेगी "तो बैश में सरणियों के लिए सही है set -o nounset। अगर आपकी परिभाषा अलग है, तो बैश थोड़ा अजीब है। देखिये मेरा अपडेटेड जवाब।
गिल्स एसओ- 10

1
विषय "बाश में, सरणियाँ एक अलग और आश्चर्यजनक तरीके से व्यवहार करती हैं।" व्यवहार को बैश (1) मैनपेज, सेक्शन "एरेस" से समझाया जा सकता है। इसमें कहा गया है कि "बिना सबस्क्रिप्ट के एक ऐरे वेरिएबल को रेफ़र करना 0. के सबस्क्रिप्ट के साथ एरे को संदर्भित करने के बराबर है।" इस प्रकार यदि न तो 0सूचकांक और न ही कुंजी को परिभाषित किया जाता है क्योंकि यह सही है a=(), ${a+1}सही ढंग से कुछ भी नहीं देता है।
टिम फ्रिसके

1
@TimFriske मुझे पता है कि बैश कार्यान्वयन इसके प्रलेखन के अनुरूप है। लेकिन एक अपरिभाषित चर की तरह एक खाली सरणी का इलाज करना वास्तव में अजीब डिजाइन है।
गिल्स एसओ- बुराई को रोकना '

मैं इस परिणाम को पसंद करता हूं: यदि बैश में एक चर सेट किया गया है तो कैसे जांचें? -> सही तरीका ... मैं एक राग के साथ हमला करता हूं कि मुझे यह कैसे काम करना चाहिए । हिम्मत मैं कहता हूं, विंडोज में एक definedऑपरेटर है। ऐसा Test कर सकते थे ; यह मुश्किल नहीं हो सकता ( उम ....)
होगा

6

गिल्स के जवाब के साथ योग करने के लिए मैंने अपने निम्नलिखित नियम बनाए:

  1. [[ -v foobar ]]बैश संस्करण में चर के लिए उपयोग करें > = 4.2।
  2. declare -p foobar &>/dev/nullबैश संस्करण में सरणी चर के लिए उपयोग करें <4.2।
  3. क्रमशः अनुक्रमित ( ) और की ( ) सरणियों ( ) की सदस्यता के लिए उपयोग करें (( ${foo[0]+1} ))या । विकल्प 1 और 2 यहां काम नहीं करते हैं।(( ${bar[foo]+1} ))-a-Adeclare

3

मैं सभी चर में एक ही तकनीक का उपयोग करता हूं, और यह काम करता है, जैसे:

[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

आउटपुट:

foobar is unset

जबकि

foobar=( "val" "val2" )
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

आउटपुट:

foobar is set

अगर [@] को हटाना है तो सरणी का एक से अधिक मूल्य है।
स्टीन इंग मोरिसबाक

1
यह महान काम करता है, इसलिए जब तक आप परीक्षण करना चाहते हैं कि क्या इसका कोई मूल्य है, न कि यह परिभाषित किया गया है। यानी, foobar=""उसके बाद रिपोर्ट करेंगे foobar is unset। कोई प्रतीक्षा नहीं, मैं उसे वापस लेता हूं। वास्तव में केवल परीक्षण करता है कि क्या पहला तत्व खाली है या नहीं, इसलिए यह केवल एक अच्छा विचार प्रतीत होता है यदि आपको पता है कि चर एक सरणी नहीं है, और आप केवल शून्यता के बारे में परवाह करते हैं, परिभाषित नहीं।
रॉन बुर्क

तभी काम करता है अपनी स्क्रिप्ट (कोई सेट -u) अपरिभाषित चर अनुमति के साथ चल रहे हैं
फ्लोरियन हीगल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.