2008-10-23 11 views
134

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

[ -z $mystr ] 

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

+26

कृपया [-z "$ mystr"] के रूप में करने का विरोध किया का उपयोग कर की आदत में हो [-z $ mystr] –

+0

कैसे उलटा बात करना है? मेरा मतलब है जब स्ट्रिंग शून्य – flow

+1

@flow नहीं है: क्या बारे में '[-n" $ {वीएआर + x} "] && गूंज – Lekensteyn

उत्तर

122

मुझे लगता है कि Vinko के answer द्वारा उत्तर दिया गया है (अगर नहीं बताया गया है), हालांकि इसे आसानी से वर्तनी नहीं दी गई है। भेद करने के लिए वीएआर सेट है कि क्या है, लेकिन खाली है या नहीं निर्धारित करते हैं, आप का उपयोग कर सकते हैं:

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

हालांकि, अगर आप पढ़ें:

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 

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

आप बैश मैनुअल में इन विवरणों और अन्य संबंधित shell parameter expansions, test or [ कमांड और conditional expressions का विवरण पा सकते हैं।


मैं हाल ही में प्रश्न के साथ इस उत्तर के बारे ईमेल द्वारा कहा गया था:

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

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= 

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

(
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} नोटेशन बनाते हैं। ${VAR-value} और ${VAR:-value}, और ${VAR+value} और ${VAR:+value}, और इसी तरह के लिए Ditto।


Gili के रूप में उसकी answer में बताते हैं, अगर आप set -o nounset विकल्प के साथ bash चलाने के लिए, तो बुनियादी जवाब ऊपर 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 +u (set -uset -o nounset के बराबर किया जा रहा है) के साथ set -o nounset विकल्प को रद्द कर सकता है।

+7

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

+3

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

+2

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

31
~> 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 अपरिभाषित चर के लिए भी काम करता है। एक अपरिभाषित और परिभाषित के बीच अंतर करने के लिए आप here सूचीबद्ध वस्तुओं का उपयोग करेंगे या स्पष्ट स्पष्टीकरण के साथ here

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

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

~$ 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

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

+1

यह उत्तर * करता है * बताता है कि उन दो मामलों के बीच अंतर कैसे करें; अधिक चर्चा के लिए प्रदान किए गए बैश फर्क लिंक का पालन करें। –

+1

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

-3

कॉल किसी भी तर्क के बिना सेट .. यह सब वार्स परिभाषित आउटपुट ..
सूची में अंतिम वाले लोगों को अपनी स्क्रिप्ट में परिभाषित किया जाएगा ..
ताकि आप कुछ है कि समझ सकता है पाइप इसके उत्पादन कर सकता है बाहर क्या चीजें परिभाषित की गई हैं और

+2

मैंने नहीं किया ' टी इसे वोट मत दें, लेकिन यह एक छोटे से अखरोट को तोड़ने के लिए एक स्लेजहैमर का कुछ है। –

+0

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

+0

ऐसा लगता है कि यह उत्तर वांछित कुछ की तुलना में "सेट" के कार्यान्वयन के दुष्प्रभाव का अधिक प्रभाव है। –

16

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

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


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

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

, अपरिभाषित, यदि isdefined = 1 चर परिभाषित किया गया था

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


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

7 का डिफ़ॉल्ट मान $ mystr करने के लिए सौंपा अगर यह अपरिभाषित था, और यह अक्षुण्ण छोड़ अन्यथा करने के लिए:

mystr=${mystr- 7} 

एक त्रुटि मुद्रित करने के लिए संदेश को हटाएं और फ़ंक्शन से बाहर निकलें यदि चर अपरिभाषित है:

: ${mystr? not defined} 

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

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

इस प्रकार के रूप में यह प्रयोग करें:

+0

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

+0

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

0

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

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

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

1

एक और विकल्प: the "list array indices" expansion:

$ 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 

किसी भी बैश संस्करण> = 3.0

7

परीक्षण का एक सारांश में उपलब्ध होना चाहिए।

[ -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" 
+0

उद्धरण क्यों? –

+0

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

+1

के खिलाफ सुरक्षा के लिए मुझे लगता है कि '$ {var + x}' के साथ यह आवश्यक नहीं है, सिवाय इसके कि चर * नाम * में रिक्त स्थान होने की अनुमति है। –

1

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

shopt -s -o nounset 

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

3

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

[ -v mystr ] 
+1

की स्थिति किसी भी मैन पेज (बैश या टेस्ट के लिए) में नहीं मिल सकती है लेकिन यह मेरे लिए काम करती है .. कोई विचार यह संस्करण किस संस्करण में जोड़ा गया था? –

+1

यह [सशर्त अभिव्यक्ति] (http://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions) में प्रलेखित है, जिसे 'टेस्ट' ऑपरेटर से पूंछ के अंत में संदर्भित किया गया है सेक्शन [बॉर्न शैल बिल्टिन्स] (http://www.gnu.org/software/bash/manual/bash.html# बॉर्न- शेल- बुबिल्टिन)। मुझे नहीं पता कि यह कब जोड़ा गया था, लेकिन यह 'bash' के ऐप्पल संस्करण में नहीं है (' bash' 3.2.51 के आधार पर), इसलिए यह शायद 4.x सुविधा है। –

+1

यह मेरे लिए 'जीएनयू बैश, संस्करण 4.1.2 (1) -release (x86_64-redhat-linux-gnu)' के साथ काम नहीं करता है। त्रुटि है '-बैश: [: -v: यूनरी ऑपरेटर अपेक्षित'। एक टिप्पणी [यहां] (http://stackoverflow.com/a/17538964/832230) के अनुसार, इसे काम करने के लिए न्यूनतम बैश 4.2 की आवश्यकता होती है। –

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 
1

Bash Reference Manual बैश के बारे में जानकारी का एक आधिकारिक स्रोत है।

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

(section 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 [email protected] 

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

संबंधित मुद्दे