यह जांचने का एक संक्षिप्त तरीका क्या है कि पर्यावरण चर एक यूनिक्स शेल स्क्रिप्ट में सेट किए गए हैं?


500

मुझे कुछ यूनिक्स शैल स्क्रिप्ट मिली हैं, जहाँ मुझे यह जाँचने की आवश्यकता है कि कुछ सामान बनाने से पहले कुछ पर्यावरण चर निर्धारित किए जाते हैं, इसलिए मैं इस प्रकार की चीज़ करता हूँ:

if [ -z "$STATE" ]; then
    echo "Need to set STATE"
    exit 1
fi  

if [ -z "$DEST" ]; then
    echo "Need to set DEST"
    exit 1
fi

जो बहुत टाइपिंग है। क्या यह जांचने के लिए अधिक सुरुचिपूर्ण मुहावरा है कि पर्यावरण चर का एक सेट निर्धारित है?

संपादित करें: मुझे यह उल्लेख करना चाहिए कि इन चरों का कोई सार्थक डिफ़ॉल्ट मान नहीं है - यदि कोई परेशान हो तो स्क्रिप्ट को त्रुटि हो जानी चाहिए।


2
इस सवाल के जवाब में से कई को लगता है कि आप कोड गोल्फ स्टैक एक्सचेंज में देखेंगे ।
डैनियल शिलिंग

जवाबों:


587

पैरामीटर विस्तार

स्पष्ट उत्तर पैरामीटर विस्तार के विशेष रूपों में से एक का उपयोग करना है:

: ${STATE?"Need to set STATE"}
: ${DEST:?"Need to set DEST non-empty"}

या, बेहतर (नीचे 'डबल कोट्स की स्थिति' पर अनुभाग देखें):

: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"

पहले संस्करण (बस का उपयोग करके ?) को सेट करने की आवश्यकता होती है, लेकिन STATE = "" (एक खाली स्ट्रिंग) ठीक है - आप जो चाहते हैं वह ठीक नहीं है, लेकिन वैकल्पिक और पुराने अंकन।

दूसरे वेरिएंट (उपयोग :?) के लिए DEST सेट और गैर-रिक्त होना आवश्यक है।

यदि आप कोई संदेश नहीं देते हैं, तो शेल एक डिफ़ॉल्ट संदेश प्रदान करता है।

${var?}निर्माण संस्करण 7 यूनिक्स और बॉर्न शैल (1978 या आस) के लिए पोर्टेबल वापस आ गया है। ${var:?}निर्माण से थोड़ा अधिक हाल है: मुझे लगता है इसे 1981 के लगभग प्रणाली III UNIX में था, लेकिन यह है कि इससे पहले कि PWB UNIX में हो सकता है। यह विशेष रूप से बैश सहित, कॉर्न शेल में और पोसिक्स के गोले में है।

इसे आमतौर पर शेल के मैन पेज में पैरामीशन एक्सपेंशन नामक सेक्शन में प्रलेखित किया जाता है । उदाहरण के लिए, bashमैनुअल कहता है:

${parameter:?word}

अशक्त या परेशान होने पर त्रुटि प्रदर्शित करें। यदि पैरामीटर अशक्त या परेशान है, तो शब्द का विस्तार (या यदि शब्द मौजूद नहीं है तो उस आशय का संदेश) मानक त्रुटि और शेल को लिखा जाता है, यदि यह संवादात्मक नहीं है, तो बाहर निकलता है। अन्यथा, पैरामीटर का मान प्रतिस्थापित किया जाता है।

बृहदान्त्र कमान

मुझे शायद यह जोड़ना चाहिए कि बृहदान्त्र कमांड में बस अपने तर्कों का मूल्यांकन किया जाता है और फिर सफल होता है। यह मूल शेल टिप्पणी संकेतन है ( #लाइन के अंत से पहले ' ')। लंबे समय तक, बॉर्न शैल लिपियों में पहले चरित्र के रूप में एक बृहदान्त्र था। सी शेल एक स्क्रिप्ट को पढ़ेगा और यह निर्धारित करने के लिए पहले वर्ण का उपयोग करेगा कि यह सी शेल ('ए #' हैश) या बॉर्न शेल ('ए :' कोलन) के लिए है या नहीं। तब कर्नेल को एक्ट में मिला और ' #!/path/to/program' के लिए समर्थन जोड़ा और बॉर्न शेल को ' #' टिप्पणियां मिलीं , और कोलन सम्मेलन रास्ते से चला गया। लेकिन अगर आप एक स्क्रिप्ट के साथ आते हैं, जो एक बृहदान्त्र से शुरू होती है, तो अब आपको पता चल जाएगा कि क्यों।


दोहरे भावों की स्थिति

ब्लोंग ने एक टिप्पणी में पूछा :

इस चर्चा पर कोई विचार? https://github.com/koalaman/shellcheck/issues/380#issuecomment-145872749

चर्चा का सार यह है:

… हालाँकि, जब मैं shellcheckइसे (संस्करण 0.4.1 के साथ), मुझे यह संदेश मिलता है:

In script.sh line 13:
: ${FOO:?"The environment variable 'FOO' must be set and non-empty"}
  ^-- SC2086: Double quote to prevent globbing and word splitting.

इस मामले में मुझे क्या करना चाहिए, इस पर कोई सलाह?

संक्षिप्त उत्तर "जैसा shellcheckकि सुझाव है" करें:

: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"

वर्णन करने के लिए क्यों, निम्नलिखित का अध्ययन करें। ध्यान दें कि :कमांड अपने तर्कों को प्रतिध्वनित नहीं करता है (लेकिन शेल तर्कों का मूल्यांकन करता है)। हम तर्कों को देखना चाहते हैं, इसलिए नीचे दिए गए कोड का उपयोग करता printf "%s\n"है :

$ mkdir junk
$ cd junk
$ > abc
$ > def
$ > ghi
$ 
$ x="*"
$ printf "%s\n" ${x:?You must set x}    # Careless; not recommended
abc
def
ghi
$ unset x
$ printf "%s\n" ${x:?You must set x}    # Careless; not recommended
bash: x: You must set x
$ printf "%s\n" "${x:?You must set x}"  # Careful: should be used
bash: x: You must set x
$ x="*"
$ printf "%s\n" "${x:?You must set x}"  # Careful: should be used
*
$ printf "%s\n" ${x:?"You must set x"}  # Not quite careful enough
abc
def
ghi
$ x=
$ printf "%s\n" ${x:?"You must set x"}  # Not quite careful enough
bash: x: You must set x
$ unset x
$ printf "%s\n" ${x:?"You must set x"}  # Not quite careful enough
bash: x: You must set x
$ 

ध्यान दें कि $xपहले *और फिर फ़ाइल नामों की एक सूची का विस्तार कैसे किया जाता है जब समग्र अभिव्यक्ति दोहरे उद्धरण चिह्नों में नहीं होती है। यह वही है जो shellcheckअनुशंसा कर रहा है उसे ठीक किया जाना चाहिए। मैंने सत्यापित नहीं किया है कि यह उस फॉर्म पर आपत्ति नहीं करता है जहां अभिव्यक्ति दोहरे उद्धरणों में संलग्न है, लेकिन यह एक उचित धारणा है कि यह ठीक होगा।


2
यही वह चीज है जिसकी मुझे जरूरत है। मैं 1987 के बाद से यूनिक्स के विभिन्न संस्करणों का उपयोग कर रहा हूं और मैंने इस वाक्यविन्यास को कभी नहीं देखा है - बस दिखाने के लिए जाता है ...
एंड्रयू 37

यह कैसे काम करता है और यह कहां से प्रलेखित है? मैं सोच रहा हूँ कि क्या यह परिवर्तनशील हो सकता है कि चर मौजूद है और एक विशिष्ट मूल्य पर सेट है।
झब्बोट

6
इसे शेल मैनुअल पेज, या बैश मैनुअल में आमतौर पर हेडर 'पैरामीटर एक्सपेंशन' के तहत प्रलेखित किया जाता है। यह जाँचने का मानक तरीका है कि क्या चर मौजूद है और एक विशिष्ट मान पर सेट है ('एबीसी' कहें) बस है if [ "$variable" = "abc" ]; then : OK; else : variable is not set correctly; fi:।
जोनाथन लेफ्लर

मैं इस वाक्यविन्यास का उपयोग उसमें स्ट्रिंग वाले चर के साथ कैसे कर सकता हूं। मुझे यह कहते हुए एक त्रुटि मिलती है कि "यह नहीं मिला:" जब मैं वैरिएबल सेट करता हूं तो मैं "यह एक परीक्षण है" की जांच करना चाहता हूं। कोई विचार?
user2294382

1
इस चर्चा पर कोई विचार? github.com/koalaman/shellcheck/issues/…
१५

138

इसे इस्तेमाल करे:

[ -z "$STATE" ] && echo "Need to set STATE" && exit 1;

8
बल्कि क्रिया है। अर्ध-बृहदान्त्र बेमानी है।
जोनाथन लेफ्लर 3

3
या इससे भी छोटा इस ब्लॉग पोस्ट को[ -z "$STATE" ] && { echo "Need to set STATE"; exit 1; } देखें
zipizap

36
जो है, वह पठनीय है। मैं इस एक के लिए कर रहा हूँ। बैश स्क्रिप्ट को उस विभाग में मिलने वाली सभी मदद की ज़रूरत होती है!
इयान डंकन

मूल उत्तर इसके सिंटैक्स में अधिक सुसंगत है।
तेजी से दाँत

4
हालाँकि, यह किसी unset वैरिएबल और वैरिएबल सेट के बीच खाली स्ट्रिंग में अंतर नहीं करता है।
शेपनर

57

आपका प्रश्न उस शेल पर निर्भर है जो आप उपयोग कर रहे हैं।

बॉर्न शेल उस रास्ते में बहुत कम निकलता है, जिसके बाद आप हैं।

परंतु...

यह काम करता है, बस हर जगह के बारे में।

बस कोशिश करें और csh से दूर रहें। बॉर्न शेल की तुलना में यह घंटी और सीटी के लिए अच्छा था, लेकिन यह वास्तव में अब चरमरा रहा है। यदि आप मुझ पर विश्वास नहीं करते हैं, तो कोशिश करें और STDERR को csh में अलग करें! (-:

यहां दो संभावनाएं हैं। ऊपर दिए गए उदाहरण का उपयोग करते हुए, अर्थात्:

${MyVariable:=SomeDefault}

पहली बार आपको $ MyVariable को संदर्भित करने की आवश्यकता है। यह env लेता है। var MyVariable और, यदि यह वर्तमान में सेट नहीं है, तो बाद के उपयोग के लिए चर के लिए SomeDefault का मान प्रदान करता है।

आपको इसकी संभावना भी है:

${MyVariable:-SomeDefault}

जहाँ आप इस निर्माण का उपयोग कर रहे हैं, जहां चर के लिए SomeDefault को प्रतिस्थापित करता है। यह वैरिएबल के लिए मान SomeDefault असाइन नहीं करता है, और MyVariable का मान इस कथन के सामने आने के बाद भी शून्य रहेगा।


3
CSH: (foo> foo.out)> & foo.err
Mr.Ree

बॉर्न शेल वह करता है जो आवश्यक है।
जोनाथन लेफ़लर

51

निश्चित रूप से सबसे सरल तरीका है -uस्विच को शेबंग (आपके स्क्रिप्ट के शीर्ष पर रेखा) में जोड़ना , यह मानते हुए कि आप उपयोग कर रहे हैं bash:

#!/bin/sh -u

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


40
${MyVariable:=SomeDefault}

यदि MyVariableसेट किया गया है और शून्य नहीं है, तो यह चर मान (= कुछ नहीं होता) को रीसेट करेगा।
और, MyVariableसेट है SomeDefault

उपरोक्त कार्य करने का प्रयास करेगा ${MyVariable}, इसलिए यदि आप केवल चर को सेट करना चाहते हैं:

MyVariable=${MyVariable:=SomeDefault}

यह संदेश उत्पन्न नहीं करता है - और क्यू कहता है कि कोई डिफ़ॉल्ट नहीं है (हालांकि यह नहीं कहा कि जब आपने अपना जवाब टाइप किया था)।
जोनाथन लेफ़लर 3

10
सही संस्करण: (1): $ {MyVariable: = SomeDefault} या (2): MyVariable = $ {MyVariable: -SomeDefault}
जोनाथन

23

मेरी राय में #! / Bin / sh के लिए सबसे सरल और सबसे संगत जाँच है:

if [ "$MYVAR" = "" ]
then
   echo "Does not exist"
else
   echo "Exists"
fi

फिर से, यह / बिन / श के लिए है और पुराने सोलारिस सिस्टम पर भी संगत है।


यह 'काम करता है', लेकिन यहां तक ​​कि पुराने सोलारिस सिस्टम के पास संकेतन का /bin/shसमर्थन ${var:?}है, आदि
जोनाथन लेफ़लर

अब तक का सबसे अच्छा जवाब।
ओले

4
खाली स्ट्रिंग पर सेट किया जाना बिल्कुल अलग नहीं है। यह परीक्षण दोनों के बाद "मौजूद नहीं है" प्रिंट करेगा unset MYVARऔर MYVAR=
शेपनर

@chepner, मैंने आपकी टिप्पणी को बहुमूल्य रूप से मूल्यवान हेड-अप के लिए उकेरा, लेकिन फिर मैंने इसे (bash के साथ) परीक्षण किया, और वास्तव में एक खाली स्ट्रिंग के लिए एक संस्करण सेट नहीं कर सका, इसके बिना भी परेशान नहीं हो सकता। आप वह कैसे करेंगें?
एस.जे.

@ Sz मुझे यकीन नहीं है कि आपका क्या मतलब है। "परेशान" का अर्थ है कि नाम का कोई मूल्य नहीं है जो इसे सौंपा गया है। अगर fooपरेशान है, फिर "$foo"भी खाली स्ट्रिंग में फैलता है।
चेपनर

17

bash4.2 ने -vऑपरेटर को प्रस्तुत किया जो किसी भी मूल्य, यहां तक ​​कि खाली स्ट्रिंग पर सेट होने पर परीक्षण करता है।

$ unset a
$ b=
$ c=
$ [[ -v a ]] && echo "a is set"
$ [[ -v b ]] && echo "b is set"
b is set
$ [[ -v c ]] && echo "c is set"
c is set

16

मैंने हमेशा इस्तेमाल किया:

if [ "x$STATE" == "x" ]; then echo "Need to set State"; exit 1; fi

इतना अधिक संक्षिप्त नहीं है, मुझे डर है।

CSH के तहत आपके पास $? STATE है।


2
यह जाँच करता है कि STATEक्या खाली या परेशान है, न कि केवल परेशान।
शेपनर

7

मेरे जैसे भविष्य के लोगों के लिए, मैं एक कदम आगे जाना चाहता था और var नाम को पैरामीटर बनाना चाहता था, इसलिए मैं वेरिएबल के वेरिएबल साइज की सूची पर लूप कर सकता हूं:

#!/bin/bash
declare -a vars=(NAME GITLAB_URL GITLAB_TOKEN)

for var_name in "${vars[@]}"
do
  if [ -z "$(eval "echo \$$var_name")" ]; then
    echo "Missing environment variable $var_name"
    exit 1
  fi
done

3

हम एक ही बार में चर का एक गुच्छा जांचने के लिए एक अच्छा अभिकथन लिख सकते हैं:

#
# assert if variables are set (to a non-empty string)
# if any variable is not set, exit 1 (when -f option is set) or return 1 otherwise
#
# Usage: assert_var_not_null [-f] variable ...
#
function assert_var_not_null() {
  local fatal var num_null=0
  [[ "$1" = "-f" ]] && { shift; fatal=1; }
  for var in "$@"; do
    [[ -z "${!var}" ]] &&
      printf '%s\n' "Variable '$var' not set" >&2 &&
      ((num_null++))
  done

  if ((num_null > 0)); then
    [[ "$fatal" ]] && exit 1
    return 1
  fi
  return 0
}

नमूना मंगलाचरण:

one=1 two=2
assert_var_not_null one two
echo test 1: return_code=$?
assert_var_not_null one two three
echo test 2: return_code=$?
assert_var_not_null -f one two three
echo test 3: return_code=$? # this code shouldn't execute

आउटपुट:

test 1: return_code=0
Variable 'three' not set
test 2: return_code=1
Variable 'three' not set

यहाँ इस तरह के और अधिक दावे: https://github.com/codeforester/base/blob/master/lib/ass/ions.sh



1

उपरोक्त समाधानों में से किसी ने भी मेरे उद्देश्यों के लिए काम नहीं किया, भाग में क्योंकि मैं एक लंबी-चौड़ी प्रक्रिया शुरू करने से पहले सेट किए जाने वाले चर की खुली सूची के लिए पर्यावरण की जांच कर रहा हूं। मैंने इसे समाप्त किया:

mapfile -t arr < variables.txt

EXITCODE=0

for i in "${arr[@]}"
do
   ISSET=$(env | grep ^${i}= | wc -l)
   if [ "${ISSET}" = "0" ];
   then
      EXITCODE=-1
      echo "ENV variable $i is required."
   fi
done

exit ${EXITCODE}

-1

बाहरी शेल स्क्रिप्ट का उपयोग करने के बजाय मैं अपने लॉगिन शेल में फ़ंक्शंस में लोड करना चाहता हूं। मैं किसी सेट चर की बजाय पर्यावरण चर की जांच करने के लिए एक सहायक फ़ंक्शन के रूप में कुछ इस तरह का उपयोग करता हूं:

is_this_an_env_variable ()
    local var="$1"
    if env |grep -q "^$var"; then
       return 0
    else
       return 1
    fi
 }

1
ये गलत है। is_this_an_env_variable Pसफलता मिलेगी क्योंकि PATHमौजूद है।
एरिक

यह मौजूद है क्योंकि यह एक पर्यावरण चर है। क्या यह सेट किया गया है eqaul nonnull स्ट्रिंग एक और मामला है।
नफ़्डे

-7

$?वाक्य रचना बहुत साफ है:

if [ $?BLAH == 1 ]; then 
    echo "Exists"; 
else 
    echo "Does not exist"; 
fi

यह काम करता है, लेकिन क्या यहां कोई जानता है कि मैं उस सिंटैक्स पर डॉक्स कहां पा सकता हूं? $? आम तौर पर पिछला रिटर्न मान होता है।
डैनी स्टेपल

मेरा बुरा - यह काम नहीं करता है। उस सेट के साथ और बिना एक सरल स्क्रिप्ट में इसे आज़माएं।
डैनी स्टेपल

11
बॉर्न, कोर्न, बैश और पोसिक्स गोले में, $?पिछले कमांड की निकास स्थिति है; $?BLAHस्ट्रिंग 'BLAH' के साथ पूर्ववर्ती कमांड के निकास की स्थिति से युक्त है। यह चर का परीक्षण बिल्कुल नहीं करता है $BLAH। (वहाँ एक अफवाह है कि यह कम या ज्यादा हो सकता है कि क्या आवश्यक है csh, लेकिन समुद्र के किनारों को समुद्र किनारे छोड़ दिया जाता है।)
जोनाथन लेफ़लर

यह पूरी तरह से गलत जवाब है जहां तक ​​बाश का सवाल है।
codeforester
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.