कैसे बताएं कि क्या एक स्ट्रिंग को बैश शेल स्क्रिप्ट में परिभाषित नहीं किया गया है


151

अगर मैं अशक्त स्ट्रिंग की जांच करना चाहता हूं तो मैं करूंगा

[ -z $mystr ]

लेकिन क्या होगा अगर मैं यह जांचना चाहता हूं कि क्या चर को परिभाषित किया गया है? या बैश स्क्रिप्टिंग में कोई भेद नहीं है?


27
कृपया [-z "$ मिस्टर"] का उपयोग करने की आदत में रहें
चार्ल्स डफी

उलटा कैसे करें? मेरा मतलब है कि जब स्ट्रिंग अशक्त नहीं है
जिस तरह से

1
@ प्रवाह: किसके बारे में[ -n "${VAR+x}"] && echo not null
Lekensteyn

1
@CharlesDuffy मैंने इससे पहले बहुत सारे ऑनलाइन संसाधनों में पढ़ा है। यह क्यों पसंद किया जाता है?
ffledgling

6
@Ayos क्योंकि अगर आपके पास उद्धरण नहीं हैं, तो चर की सामग्री स्ट्रिंग-विभाजित और ग्लोबेड है; अगर यह एक खाली स्ट्रिंग है, तो [ -z ]इसके बजाय बन जाता है [ -z "" ]; यदि इसमें रिक्त स्थान हैं, तो यह [ -z "my" "test" ]इसके बजाय बन जाता है [ -z my test ]; और यदि यह है [ -z * ], तो *आपकी निर्देशिका में फ़ाइलों के नाम से बदल दिया गया है।
चार्ल्स डफी

जवाबों:


138

मैं द्वारा जवाब आप के बाद कर रहे हैं निहित है लगता है (यदि यह नहीं बताया) Vinko के जवाब है, हालांकि यह बस से बताया नहीं है। यह जानने के लिए कि VAR सेट है या खाली या सेट नहीं है, आप उपयोग कर सकते हैं:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

आप शायद दूसरी पंक्ति में दो परीक्षणों को एक साथ जोड़ सकते हैं:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

हालाँकि, यदि आप ऑटोकॉन्फ़ के लिए दस्तावेज़ीकरण पढ़ते हैं, तो आप पाएंगे कि वे ' -a' के साथ शब्दों को संयोजित करने की अनुशंसा नहीं करते हैं और अलग-अलग परीक्षण परीक्षणों का उपयोग करने की अनुशंसा करते हैं&& । मैंने एक ऐसी प्रणाली का सामना नहीं किया है जहाँ कोई समस्या है; इसका मतलब यह नहीं है कि वे अस्तित्व में नहीं थे (लेकिन वे शायद इन दिनों बहुत दुर्लभ हैं, भले ही वे सुदूर अतीत में उतने दुर्लभ न हों)।

आप बश नियमावली में इनका विवरण और अन्य संबंधित शेल पैरामीटर विस्तार , testया[ कमांड और सशर्त अभिव्यक्ति पा सकते हैं ।


मुझे इस सवाल के जवाब के बारे में ईमेल द्वारा हाल ही में पूछा गया था:

आप दो परीक्षणों का उपयोग करते हैं, और मैं दूसरे को अच्छी तरह समझता हूं, लेकिन पहले वाले को नहीं। अधिक सटीक रूप से मैं चर विस्तार की आवश्यकता को नहीं समझता

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi

क्या यह पूरा नहीं होगा?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi

निष्पक्ष प्रश्न - इसका उत्तर है 'नहीं, आपका सरल विकल्प एक ही काम नहीं करता है'।

मान लीजिए कि मैं आपके परीक्षण से पहले यह लिखता हूं:

VAR=

आपका परीक्षण यह कहेगा कि "VAR बिल्कुल सेट नहीं है", लेकिन मेरा कहना होगा (निहितार्थ से क्योंकि यह कुछ भी नहीं निकालता है) "VAR सेट है लेकिन इसका मान खाली हो सकता है"। इस स्क्रिप्ट का प्रयास करें:

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:2 VAR is not set at all; fi
)

आउटपुट है:

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

परीक्षणों की दूसरी जोड़ी में, चर सेट किया गया है, लेकिन यह रिक्त मान पर सेट है। यही वह भेद है जिसे ${VAR=value}और ${VAR:=value}धारणाएँ बनाती हैं। Ditto के लिए , ${VAR-value}और ${VAR:-value}, ${VAR+value}और ${VAR:+value}, और इतने पर।


जैसा कि गिल्ली अपने जवाब में बताती है , यदि आप विकल्प के bashसाथ चलते हैं set -o nounset, तो ऊपर दिया गया मूल उत्तर विफल हो जाता है unbound variable। इसे आसानी से मिटा दिया जाता है:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

या आप (इसके समतुल्य होने के set -o nounsetसाथ ) विकल्प को रद्द कर सकते हैं ।set +uset -uset -o nounset


7
इस जवाब के साथ मेरे पास एकमात्र समस्या यह है कि यह एक अप्रत्यक्ष और अस्पष्ट फैशन में अपने काम को पूरा करता है।
स्विस

3
उन लोगों के लिए जो बैश मैन पेज में उपर्युक्त साधनों के विवरण की तलाश करना चाहते हैं, वे खंड "पैरामीटर विस्तार" की तलाश करें और फिर इस पाठ के लिए: "जब सब्स्टिट्यूट विस्तार का प्रदर्शन नहीं किया जाता है, तो नीचे दिए गए प्रपत्रों का उपयोग करके, बैश परीक्षणों के लिए एक पैरामीटर जो परेशान या अशक्त है ['null' जिसका अर्थ है रिक्त स्ट्रिंग]] केवल एक पैरामीटर के लिए एक परीक्षण में बृहदान्त्र परिणामों को छोड़ना जो कि परेशान है (...) $ {पैरामीटर: + शब्द}: वैकल्पिक मान का उपयोग करें। यदि पैरामीटर अशक्त या परेशान है, कुछ भी प्रतिस्थापित नहीं है, अन्यथा शब्द का विस्तार प्रतिस्थापित है। "
डेविड टोनहोफर

2
@Swiss यह न तो अस्पष्ट है और न ही अप्रत्यक्ष, बल्कि मुहावरेदार है। शायद एक प्रोग्रामर के साथ अपरिचित ${+}और ${-}यह अस्पष्ट है, लेकिन उन निर्माणों के साथ परिचित होना आवश्यक है यदि कोई शेल का एक सक्षम उपयोगकर्ता होना चाहिए।
विलियम पर्ससेल

यदि आप इसे सक्षम के साथ लागू करना चाहते हैं, तो stackoverflow.com/a/20003892/14731 देखें set -o nounset
जिली

मैंने इस पर बहुत परीक्षण किया; क्योंकि मेरी लिपियों में परिणाम असंगत थे। मेरा सुझाव है कि bash -s v4.2 और उससे आगे के " [ -v VAR ]" लोक दृष्टिकोण पर ध्यान दें ।
होगा

38
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-z अपरिभाषित चरों के लिए भी काम करता है। एक अपरिभाषित और परिभाषित के बीच अंतर करने के लिए आप यहां सूचीबद्ध चीजों का उपयोग करेंगे या स्पष्ट स्पष्टीकरण के साथ, यहां

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

वैकल्पिक शब्द:

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

डिफ़ॉल्ट मान:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

बेशक, आप इनमें से किसी एक का उपयोग करेंगे, 'डिफ़ॉल्ट मान' के बजाय आप जो मूल्य चाहते हैं, और उचित होने पर सीधे विस्तार का उपयोग करें।


1
लेकिन मैं इस बात में अंतर करना चाहता हूं कि क्या स्ट्रिंग "" है या इसे कभी परिभाषित नहीं किया गया है। क्या यह संभव है?
सेटजम्प

1
इस जवाब है कि उन दो मामलों के बीच अंतर करना बताओ; यह चर्चा के लिए प्रदान करता है बाश faq लिंक का पालन करें।
चार्ल्स डफी

1
मैंने कहा कि उनकी टिप्पणी के बाद, चार्ल्स
विंको वर्सालोविच

2
इन सभी "ट्रिक्स" के लिए बैश मैन पेज में "पैरामीटर एक्सपेंशन" देखें। उदाहरण के लिए $ {foo: -default} डिफ़ॉल्ट मान, $ {foo: = default} का उपयोग करने के लिए डिफ़ॉल्ट मान, $ {foo: त्रुटि संदेश} को असाइन करने के लिए त्रुटि संदेश प्रदर्शित करने के लिए यदि फू परेशान है, आदि
Jounger K । सेप्पानेन

18

उन्नत बैश स्क्रिप्टिंग गाइड, 10.2। पैरामीटर प्रतिस्थापन:

  • $ {var + blahblah}: यदि var को परिभाषित किया जाता है, तो 'blahblah' को अभिव्यक्ति के लिए प्रतिस्थापित किया जाता है, अन्यथा नल को प्रतिस्थापित किया जाता है
  • $ {var-blahblah}: यदि var को परिभाषित किया जाता है, तो इसे स्वयं प्रतिस्थापित किया जाता है, अन्यथा 'blahblah' प्रतिस्थापित किया जाता है
  • $ {var; blahblah}: यदि var को परिभाषित किया जाता है, तो इसे प्रतिस्थापित किया जाता है, अन्यथा फ़ंक्शन त्रुटि संदेश के रूप में 'blahblah' के साथ मौजूद होता है।


चर $ रहस्य को परिभाषित किया गया है या नहीं, इस पर अपने कार्यक्रम के तर्क को आधार बनाने के लिए, आप निम्नलिखित कार्य कर सकते हैं:

isdefined=0
${mystr+ export isdefined=1}

अब, यदि अपरिभाषित = 0 है तो चर अपरिभाषित था, यदि अपरिभाषित = 1 चर को परिभाषित किया गया था

चर की जाँच करने का यह तरीका उपरोक्त उत्तर से बेहतर है क्योंकि यह अधिक सुरुचिपूर्ण, पठनीय है, और यदि आपके बैश शेल को अपरिभाषित चर के उपयोग पर त्रुटि के लिए कॉन्फ़िगर किया गया था (set -u), तो स्क्रिप्ट समय से पहले समाप्त हो जाएगी।


अन्य उपयोगी सामान:

यदि यह अपरिभाषित था, तो $ 7 मैस्टर को एक डिफ़ॉल्ट मान दिया जाना चाहिए, और इसे अन्यथा छोड़ दें:

mystr=${mystr- 7}

यदि कोई त्रुटि नहीं है, तो त्रुटि संदेश प्रिंट करें और फ़ंक्शन से बाहर निकलें:

: ${mystr? not defined}

यहाँ से सावधान रहें कि मैंने ':' का उपयोग किया ताकि $ कमांडर की सामग्री को कमांड के रूप में निष्पादित न किया जा सके, क्योंकि यह परिभाषित है।


मुझे इसके बारे में पता नहीं था? बैश चर के लिए वाक्यविन्यास। यह एक अच्छी कैच है।
स्विस

यह अप्रत्यक्ष चर संदर्भों के साथ भी काम करता है। यह गुजरता है: var= ; varname=var ; : ${!varname?not defined}और यह समाप्त होता है varname=var ; : ${!varname?not defined}:। लेकिन इसका इस्तेमाल करना एक अच्छी आदत है set -uजो उतना ही आसान है।
ceving

11

परीक्षणों का सारांश।

[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set"  # may or may not be empty
[ -n "${var+x}" ] && echo "var is set"  # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"

बैश में अच्छा अभ्यास। कभी-कभी फ़ाइल पथ में रिक्त स्थान होता है, या कमांड इंजेक्शन से बचाने के लिए
k107

1
मुझे लगता है कि ${var+x}यह आवश्यक नहीं है सिवाय इसके कि अगर चर नामों को उन में स्थान रखने की अनुमति हो।
ऐनी वैन रोसम

सिर्फ अच्छा अभ्यास नहीं; यह है की आवश्यकता के साथ [सही परिणाम प्राप्त करने के। अगर varपरेशान या खाली है, तो [ -n $var ]कम हो जाता है, [ -n ]जिसमें बाहर निकलने की स्थिति 0 है, जबकि [ -n "$var" ]अपेक्षित (और सही) 1 से बाहर निकलने की स्थिति है
chepner

5

https://stackoverflow.com/a/9824943/14731 में बेहतर उत्तर है (जो अधिक पठनीय है और set -o nounsetसक्षम के साथ काम करता है )। यह इस तरह मोटे तौर पर काम करता है:

if [ -n "${VAR-}" ]; then
    echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
    echo "VAR is set, but empty"
else
    echo "VAR is not set"
fi

4

एक चर परिभाषित करने के लिए जाँच करने का स्पष्ट तरीका होगा:

[ -v mystr ]

1
यह किसी भी आदमी के पन्नों (bash या परीक्षण के लिए) में नहीं मिल सकता है, लेकिन यह मेरे लिए काम करता है .. किसी भी विचार क्या यह संस्करण जोड़ा गया था?
राख बर्लिन-टेलर

1
यह सशर्त अभिव्यक्तियों में प्रलेखित है , testअनुभाग बॉर्न शेल बिल्डिंस के टेल एंड में ऑपरेटर से संदर्भित है । मुझे नहीं पता कि इसे कब जोड़ा गया था, लेकिन यह bash( bash3.2.51 पर आधारित ) के Apple संस्करण में नहीं है , इसलिए यह संभवतः एक 4.50 फ़ीचर है।
जोनाथन लेफ्लर

1
यह मेरे साथ काम नहीं करता है GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)। त्रुटि है -bash: [: -v: unary operator expectedयहां एक टिप्पणी के अनुसार , इसे काम करने के लिए न्यूनतम बैश 4.2 की आवश्यकता होती है।
एक्यूमेनस

जाँच के लिए धन्यवाद जब यह उपलब्ध हो गया। मैंने पहले विभिन्न प्रणालियों पर इसका उपयोग किया था, लेकिन फिर अचानक यह काम नहीं किया। मैं यहाँ जिज्ञासा से बाहर आया और हाँ, बेशक इस प्रणाली पर बैश एक 3.x बैश है।
15

1

एक अन्य विकल्प: "सूची सरणी सूचकांक" विस्तार :

$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1

केवल यह समय खाली स्ट्रिंग तक फैलता है foo होता होती आप परेशान होते हैं, इसलिए आप इसे स्ट्रिंग सशर्त के साथ देख सकते हैं:

$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0

किसी भी bash संस्करण> = 3.0 में उपलब्ध होना चाहिए


1

इस बाइक को आगे भी शेड नहीं करना है, लेकिन जोड़ना चाहते हैं

shopt -s -o nounset

एक स्क्रिप्ट के शीर्ष पर आप कुछ जोड़ सकते हैं, जो स्क्रिप्ट में कहीं भी चर घोषित नहीं होने पर त्रुटि करेगा । आपके द्वारा देखा गया संदेश है unbound variable, लेकिन जैसा कि अन्य उल्लेख करते हैं कि यह एक रिक्त स्ट्रिंग या अशक्त मान नहीं पकड़ेगा। यह सुनिश्चित करने के लिए कि कोई भी व्यक्तिगत मान रिक्त नहीं है, हम एक चर का परीक्षण कर सकते हैं, क्योंकि इसका विस्तार ${mystr:?}डॉलर चिह्न विस्तार के रूप में भी किया जाता है, जिसके साथ त्रुटि होगी parameter null or not set


1

बैश संदर्भ मैनुअल बैश के बारे में जानकारी का एक आधिकारिक स्रोत है।

यदि यह मौजूद है, तो यह देखने के लिए एक चर का परीक्षण करने का एक उदाहरण है:

if [ -z "$PS1" ]; then
        echo This shell is not interactive
else
        echo This shell is interactive
fi

( खंड 6.3.2 से )

ध्यान दें कि खुले के बाद खाली स्थान के [और इससे पहले कि ]है वैकल्पिक नहीं


विम उपयोगकर्ताओं के लिए युक्तियाँ

मेरे पास एक स्क्रिप्ट थी जिसमें कई घोषणाएँ थीं:

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

लेकिन मैं चाहता था कि वे किसी भी मौजूदा मूल्यों को टाल दें। इसलिए मैंने उन्हें ऐसा दिखने के लिए फिर से लिखा:

if [ -z "$VARIABLE_NAME" ]; then
        export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi

मैं एक त्वरित regex का उपयोग करके इसे vim में स्वचालित करने में सक्षम था:

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r  export \1=\2\rfi\r/gc

यह संबंधित लाइनों को नेत्रहीन, फिर टाइप करके चुन सकते हैं :। कमांड बार पहले से पॉप-अप हो जाता है :'<,'>। उपरोक्त कमांड को पेस्ट करें और एंटर दबाएं।


विम के इस संस्करण पर परीक्षण किया गया:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by root@apple.com

विंडोज उपयोगकर्ता अलग लाइन अंत चाहते हो सकता है।


0

यहाँ मुझे लगता है कि एक चर को परिभाषित करने के लिए जाँच करने का एक बहुत ही स्पष्ट तरीका है:

var_defined() {
    local var_name=$1
    set | grep "^${var_name}=" 1>/dev/null
    return $?
}

इसे निम्नानुसार उपयोग करें:

if var_defined foo; then
    echo "foo is defined"
else
    echo "foo is not defined"
fi

1
एक फ़ंक्शन लिखना एक बुरा विचार नहीं है; आहट grepभयानक है। ध्यान दें कि एक चर के मूल्य को प्राप्त करने के तरीके के रूप में bashसमर्थन करता है ${!var_name}जिसका नाम निर्दिष्ट है $var_name, इसलिए name=value; value=1; echo ${name} ${!name}पैदावार value 1
जोनाथन लेफलर

0

अपरिभाषित चर का परीक्षण करने के लिए एक छोटा संस्करण बस हो सकता है:

test -z ${mystr} && echo "mystr is not defined"

-3

बिना किसी तर्क के कॉल सेट .. यह सभी वर्सेज़ को डिफाइन करता है ..
लिस्ट में आख़िरी वाले आपकी स्क्रिप्ट में परिभाषित होंगे।
इसलिए आप इसके आउटपुट को किसी ऐसी चीज़ से पाइप कर सकते हैं जो यह पता लगा सके कि क्या चीज़ें परिभाषित हैं और क्या नहीं


2
मैंने इसे वोट नहीं दिया, लेकिन यह एक छोटे नट को दरार करने के लिए एक स्लेजहैमर के कुछ है।
जोनाथन लेफ़लर

मुझे वास्तव में स्वीकृत उत्तर से बेहतर यह उत्तर पसंद है। यह स्पष्ट है कि इस उत्तर में क्या किया जा रहा है। स्वीकार किया गया उत्तर नरक के रूप में जीता है।
स्विस

ऐसा लगता है कि यह उत्तर "सेट" के कार्यान्वयन के एक पक्ष-प्रभाव से अधिक है जो वांछनीय है।
जोनाथन मॉर्गन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.