चर विस्तार को कैसे स्थगित करें


18

मैं अपनी स्क्रिप्ट के शीर्ष पर कुछ स्ट्रिंग को इनिशियलाइज़ करना चाहता था, जिन्हें अभी तक सेट नहीं किया गया है, जैसे:

str1='I went to ${PLACE} and saw ${EVENT}'
str2='If you do ${ACTION} you will ${RESULT}'

और फिर बाद में PLACE, EVENT, ACTION, और RESULTस्थापित किया जाएगा। मैं तब विस्तार करने वाले चरों के साथ अपने तार को प्रिंट करना चाहता हूं। क्या मेरा एकमात्र विकल्प है eval? यह काम करने लगता है:

eval "echo ${str1}"

क्या यह मानक है? क्या ऐसा करने के लिए इससे अच्छा तरीका है? evalवेरिएबल्स कुछ भी हो सकता है, इस पर विचार नहीं करना अच्छा होगा ।

जवाबों:


23

आपके द्वारा दिखाए जाने वाले इनपुट के साथ, शेल में स्थानापन्न मूल्यों में शेल विस्तार का लाभ उठाने का एकमात्र तरीका evalकिसी न किसी रूप में उपयोग करना है। यह तब तक सुरक्षित है जब तक आप इसके मूल्य को नियंत्रित करते हैं str1और यह सुनिश्चित कर सकते हैं कि यह केवल उन चरों का संदर्भ देता है जिन्हें सुरक्षित (गोपनीय डेटा नहीं) के रूप में जाना जाता है और इसमें कोई अन्य अनछुए शेल विशेष वर्ण नहीं होते हैं। आप दोहरे उद्धरण चिह्नों के अंदर या यहाँ दस्तावेज़ में स्ट्रिंग का विस्तार करना चाहिए, कि जिस तरह से केवल "$\`विशेष कर रहे हैं (वे एक से पहले करने की आवश्यकता \मेंstr1 )।

eval "substituted=\"$str1\""

यह एक स्ट्रिंग के बजाय एक फ़ंक्शन को परिभाषित करने के लिए बहुत अधिक मजबूत होगा।

fill_template () {
  sentence1="I went to ${PLACE} and saw ${EVENT}"
  sentence2="If you do ${ACTION} you will ${RESULT}"
}

चर सेट करें फिर fill_templateआउटपुट चर सेट करने के लिए फ़ंक्शन को कॉल करें ।

PLACE=Sydney; EVENT=fireworks
ACTION='not learn from history'; RESULT='have to relive history'
fill_template
echo "During my holidays, $sentence1."
echo "Cicero said: \"$sentence2\"."

2
मूल्यांकन में देरी और स्पष्ट निकासी कॉल से बचने के लिए एक फ़ंक्शन का उपयोग करके अच्छा काम।
क्लेटन स्टेनली

अच्छा समाधान, इससे मुझे बहुत मदद मिली। धन्यवाद!
स्टुअर्ट

8

जैसा कि मैं आपका अर्थ लेता हूं, मुझे विश्वास नहीं है कि इनमें से कोई भी उत्तर सही है। evalकिसी भी तरह से आवश्यक नहीं है, और न ही आपको अपने चर का दो बार मूल्यांकन करने की कोई आवश्यकता है।

यह सच है, @Gilles बहुत करीब आता है, लेकिन वह संभवतः ओवरराइडिंग मानों की समस्या को संबोधित नहीं करता है और यदि आपको उन्हें एक से अधिक बार आवश्यकता होती है तो उनका उपयोग कैसे किया जाना चाहिए। आखिरकार, एक टेम्पलेट का उपयोग एक से अधिक बार किया जाना चाहिए, है ना?

मुझे लगता है कि यह अधिक क्रम है जिसमें आप उनका मूल्यांकन करते हैं जो महत्वपूर्ण है। निम्नलिखित को धयान मे रखते हुए:

ऊपर

यहां आप कुछ डिफॉल्ट सेट करेंगे और उन्हें कॉल करने के लिए प्रिंट करने की तैयारी करेंगे ...

#!/bin/sh
    _top_of_script_pr() ( 
        IFS="$nl" ; set -f #only split at newlines and don't expand paths
        printf %s\\n ${strings}
    ) 3<<-TEMPLATES
        ${nl=
}
        ${PLACE:="your mother's house"}
        ${EVENT:="the unspeakable."}
        ${ACTION:="heroin"}
        ${RESULT:="succeed."}
        ${strings:="
            I went to ${PLACE} and saw ${EVENT}
            If you do ${ACTION} you will ${RESULT}
        "}
    #END
    TEMPLATES

मध्य

यह वह जगह है जहाँ आप अपने परिणामों के आधार पर अपने प्रिंट फ़ंक्शन पर कॉल करने के लिए अन्य कार्यों को परिभाषित करते हैं ...

    EVENT="Disney on Ice."
    _more_important_function() { #...some logic...
        [ $((1+one)) -ne 2 ] && ACTION="remedial mathematics"
            _top_of_script_pr
    }
    _less_important_function() { #...more logic...
        one=2
        : "${ACTION:="calligraphy"}"
        _top_of_script_pr
    }

तल

अब आपको यह सब सेटअप मिल गया है, इसलिए यहां आप अपने परिणामों को निष्पादित और खींच लेंगे।

    _less_important_function
    : "${PLACE:="the cemetery"}" 
    _more_important_function
    : "${RESULT:="regret it."}" 
    _less_important_function    

परिणाम

मैं एक पल में क्यों अंदर जाऊंगा, लेकिन ऊपर चलने से निम्नलिखित परिणाम मिलते हैं:

_less_important_function()'s प्रथम रन:

मैं आपकी माँ के घर गया और बर्फ पर डिज्नी को देखा

यदि आप सुलेख करते हैं तो आप सफल होंगे।

फिर _more_important_function():

मैं कब्रिस्तान गया और बर्फ पर डिज्नी को देखा।

यदि आप सुधारात्मक गणित करेंगे तो आप सफल होंगे।

_less_important_function() फिर:

मैं कब्रिस्तान गया और बर्फ पर डिज्नी को देखा।

यदि आप उपचारात्मक गणित करते हैं तो आपको इसका पछतावा होगा।

यह काम किस प्रकार करता है:

यहाँ की प्रमुख विशेषता यह है कि conditional ${parameter} expansion.आप किसी वैरिएबल को किसी मान पर सेट कर सकते हैं, यदि यह प्रपत्र का उपयोग करने के लिए परेशान या अशक्त हो:

${var_name: =desired_value}

यदि इसके बजाय आप केवल एक अस्थिर चर सेट करना चाहते हैं, तो आप छोड़ देंगे :colonऔर अशक्त मान जैसा है वैसा ही रहेगा।

SCOPE पर:

आप देख सकते हैं कि उपरोक्त उदाहरण में $PLACEऔर $RESULTजब पहले से ही कॉल किया गया हो तब parameter expansionभी बदल _top_of_script_pr()जाता है, संभवत: इसे चलाने पर उन्हें सेट किया जा सकता है। इसका कारण यह है कि _top_of_script_pr()यह एक ( subshelled )फ़ंक्शन है - मैंने इसे दूसरों के लिए उपयोग किए जाने के parensबजाय संलग्न { curly braces }किया। क्योंकि इसे एक उप-संस्करण में कहा जाता है, प्रत्येक चर जो इसे सेट करता है locally scopedऔर जैसे ही यह अपने मूल शेल में लौटता है, वे मान गायब हो जाते हैं।

लेकिन जब _more_important_function()सेट $ACTIONहोता है globally scopedतो यह _less_important_function()'sदूसरे मूल्यांकन को प्रभावित करता है $ACTIONक्योंकि _less_important_function()सेट $ACTIONकेवल के माध्यम से होता है${parameter:=expansion}.

:शून्य

और मैं अग्रणी :colon?खैर का उपयोग क्यों करता हूं , manपृष्ठ आपको बताएगा कि : does nothing, gracefully.आप देखते हैं, parameter expansionवास्तव में यह कैसा लगता है - यह expandsउस मूल्य के लिए है ${parameter}.जब हम एक चर सेट करते हैं जब हम ${parameter:=expansion}इसके मूल्य के साथ छोड़ देते हैं - जो शेल करेगा लाइन में निष्पादित करने का प्रयास। अगर इसे चलाने की कोशिश की गई तो यह the cemeteryआप पर कुछ गलतियाँ करेगा। PLACE="${PLACE:="the cemetery"}"उसी परिणाम का उत्पादन करेगा, लेकिन यह इस मामले में भी बेमानी है और मैंने उस शेल को प्राथमिकता दी: ${did:=nothing, gracefully}.

यह आपको ऐसा करने की अनुमति देता है:

    echo ${var:=something or other}
    echo $var
something or other
something or other

यहाँ-दस्तावेजों

और वैसे - एक अशक्त या परेशान चर की इन-लाइन परिभाषा यह भी है कि निम्नलिखित कार्य क्यों किए जाते हैं:

    <<HEREDOC echo $yo
        ${yo=yoyo}
    HEREDOC
yoyo

एक के बारे में सोचने का सबसे अच्छा तरीका है here-document एक इनपुट फ़ाइल-डिस्क्रिप्टर पर स्ट्रीम की गई वास्तविक फ़ाइल है। कमोबेश यही वे हैं, लेकिन अलग-अलग गोले उन्हें थोड़ा अलग तरीके से लागू करते हैं।

किसी भी स्थिति में, यदि आप उद्धरण नहीं करते हैं, तो आप <<LIMITERइसे स्ट्रीम में प्राप्त कर सकते हैं और मूल्यांकन किया जा सकता है expansion.ताकि कैन here-documentकाम में एक वैरिएबल की घोषणा कर सके, लेकिन केवल expansionजिसके माध्यम से आप केवल वैरिएबल सेट करने के लिए सीमित कर सकते हैं जो पहले से सेट नहीं हैं। फिर भी, यह पूरी तरह से आपकी आवश्यकताओं के अनुरूप है जैसा कि आपने उन्हें वर्णित किया है, क्योंकि जब आप अपने टेम्पलेट प्रिंट फ़ंक्शन को कॉल करते हैं तो आपके डिफ़ॉल्ट मान हमेशा सेट होंगे।

क्यों नहीं eval?

खैर, मैंने जो उदाहरण प्रस्तुत किया है वह स्वीकार करने का एक सुरक्षित और प्रभावी साधन प्रदान करता है parameters.क्योंकि यह गुंजाइश को संभालता है, सेट के माध्यम से प्रत्येक चर ${parameter:=expansion}बाहर से निश्चित है। इसलिए, यदि आप यह सब एक स्क्रिप्ट में डालते हैं, जिसे कहा जाता है template_pr.sh और भाग गया:

 % RESULT=something_else template_pr.sh

आपको मिलेगा:

मैं आपकी माँ के घर गया और बर्फ पर डिज्नी को देखा

यदि आप सुलेख करते हैं तो आप some_else करेंगे

मैं कब्रिस्तान गया और बर्फ पर डिज्नी को देखा

यदि आप उपचारात्मक गणित करते हैं तो आप some_else करेंगे

मैं कब्रिस्तान गया और बर्फ पर डिज्नी को देखा

यदि आप उपचारात्मक गणित करते हैं तो आप some_else करेंगे

यह उन चरों के लिए काम नहीं करेगा जो शाब्दिक रूप से स्क्रिप्ट में सेट थे, जैसे कि $EVENT, $ACTION,और $one,लेकिन मैंने केवल अंतर प्रदर्शित करने के लिए उन तरीकों को परिभाषित किया था।

किसी भी मामले में, एक evaledबयान में अज्ञात इनपुट की स्वीकृति स्वाभाविक रूप से असुरक्षित है, जबकि parameter expansionविशेष रूप से इसे करने के लिए डिज़ाइन किया गया है।


1

आप unexpanded चर के बजाय स्ट्रिंग टेम्पलेट्स के लिए प्लेसहोल्डर का उपयोग कर सकते हैं। यह बहुत जल्दी गड़बड़ हो जाएगा। यदि आप जो कर रहे हैं वह बहुत भारी है, तो आप एक वास्तविक टेम्पलेट लाइब्रेरी वाली भाषा पर विचार करना चाह सकते हैं।

format_template() {
    changed_str=$1

    for word in $changed_str; do
        if [[ $word == %*% ]]; then
            var="${word//\%/}"
            changed_str="${changed_str//$word/${!var}}"
        fi
    done
}

str1='I went to %PLACE% and saw %EVENT%'
PLACE="foo"
EVENT="bar"
format_template "$str1"
echo "$changed_str"

ऊपर से नकारात्मक पक्ष यह है कि टेम्प्लेट चर का स्वयं का शब्द होना चाहिए (जैसे आप ऐसा नहीं कर सकते "%prefix%foo")। यह कुछ संशोधनों के साथ तय किया जा सकता है, या बस इसे गतिशील होने के बजाय टेम्प्लेट चर को हार्ड-कोड करके।

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