अद्यतन: कुछ लोगों का कहना है कि किसी को भी- eval का उपयोग करना चाहिए। मैं असहमत हूं। मुझे लगता है कि जोखिम तब होता है जब भ्रष्ट इनपुट को पारित किया जा सकता है eval
। हालाँकि ऐसी कई सामान्य स्थितियाँ हैं जहाँ यह जोखिम नहीं है, और इसलिए यह जानने योग्य है कि किसी भी स्थिति में इसका उपयोग कैसे किया जाए। यह स्टैकओवरफ़्लो उत्तर स्पष्ट करने के विकल्प और eval के विकल्प बताता है। अंततः यह निर्धारित करने के लिए उपयोगकर्ता पर निर्भर है कि क्या / जब eval सुरक्षित है और उपयोग करने के लिए कुशल है।
बैश eval
स्टेटमेंट आपको अपने बैश स्क्रिप्ट द्वारा गणना की गई या अधिग्रहीत कोड की लाइनों को निष्पादित करने की अनुमति देता है।
शायद सबसे सीधा उदाहरण एक बैश प्रोग्राम होगा जो टेक्स्ट फाइल के रूप में एक और बैश स्क्रिप्ट खोलता है, टेक्स्ट की प्रत्येक पंक्ति को पढ़ता है, और eval
उन्हें क्रम में निष्पादित करने के लिए उपयोग करता है। यह अनिवार्य रूप से बैश source
स्टेटमेंट के समान व्यवहार है , जो कि एक का उपयोग करेगा, जब तक कि आयातित स्क्रिप्ट की सामग्री पर किसी प्रकार का परिवर्तन (जैसे फ़िल्टरिंग या प्रतिस्थापन) करना आवश्यक नहीं था।
मुझे शायद ही कभी आवश्यकता होती है eval
, लेकिन मैंने उन चर को पढ़ना या लिखना उपयोगी पाया है जिनके नाम अन्य चर को सौंपे गए तार में समाहित थे। उदाहरण के लिए, चर के सेट पर कार्रवाई करना, जबकि कोड पदचिह्न को छोटा रखना और अतिरेक से बचना।
eval
वैचारिक रूप से सरल है। हालाँकि, बैश भाषा के सख्त सिंटैक्स, और बैश दुभाषिया के पार्सिंग क्रम को बारीक किया जा सकता है और यह eval
क्रिप्टिक और उपयोग करने या समझने में मुश्किल हो सकता है। यहाँ आवश्यक हैं:
पास किया गया तर्क eval
एक स्ट्रिंग अभिव्यक्ति है जिसे रनटाइम पर परिकलित किया जाता है। अपनी स्क्रिप्ट में कोड की वास्तविक लाइन के eval
रूप में इसके तर्क के अंतिम पार्स किए गए परिणाम को निष्पादित करेगा ।
सिंटेक्स और पार्सिंग क्रम कड़े हैं। यदि परिणाम आपकी स्क्रिप्ट के दायरे में बैश कोड की एक निष्पादन योग्य रेखा नहीं है, तो प्रोग्राम उस eval
कथन पर क्रैश हो जाएगा क्योंकि यह कचरा निष्पादित करने का प्रयास करता है।
परीक्षण करते समय आप eval
स्टेटमेंट को बदल सकते हैं echo
और जो प्रदर्शित होता है उसे देख सकते हैं। यदि यह वर्तमान संदर्भ में वैध कोड है, तो इसे चलाने से eval
काम चल जाएगा।
निम्नलिखित उदाहरण स्पष्ट करने में मदद कर सकते हैं कि कैसे काम करता है ...
उदाहरण 1:
eval
'सामान्य' कोड के सामने बयान एक एनओपी है
$ eval a=b
$ eval echo $a
b
उपरोक्त उदाहरण में, पहले eval
बयानों का कोई उद्देश्य नहीं है और इसे समाप्त किया जा सकता है। eval
पहली पंक्ति में व्यर्थ है क्योंकि कोड के लिए कोई गतिशील पहलू नहीं है, अर्थात यह पहले से ही bash कोड की अंतिम पंक्तियों में पार्स हो गया है, इस प्रकार यह bash स्क्रिप्ट में कोड के एक सामान्य कथन के समान होगा। 2 eval
भी व्यर्थ है, क्योंकि, हालांकि एक $a
शाब्दिक चरण है जो इसके शाब्दिक स्ट्रिंग समतुल्य में परिवर्तित होता है, कोई अप्रत्यक्षता नहीं है (उदाहरण के लिए वास्तविक बैश संज्ञा या बैश-आयोजित स्क्रिप्ट चर के स्ट्रिंग मान के माध्यम से कोई संदर्भ नहीं है ), इसलिए यह पहचान का व्यवहार करेगा eval
उपसर्ग के बिना कोड की एक पंक्ति के रूप में ।
उदाहरण 2:
स्ट्रिंग मानों के रूप में दिए गए var नामों का उपयोग करके var असाइनमेंट निष्पादित करें।
$ key="mykey"
$ val="myval"
$ eval $key=$val
$ echo $mykey
myval
यदि आप थे echo $key=$val
, तो आउटपुट होगा:
mykey=myval
यह , स्ट्रिंग पार्सिंग का अंतिम परिणाम है, जो कि निष्कासन द्वारा निष्पादित किया जाएगा, इसलिए अंत में गूंज कथन का परिणाम ...
उदाहरण 3:
उदाहरण 2 में अधिक अप्रत्यक्ष जोड़ना
$ keyA="keyB"
$ valA="valB"
$ keyB="that"
$ valB="amazing"
$ eval eval \$$keyA=\$$valA
$ echo $that
amazing
उपरोक्त पिछले उदाहरण की तुलना में थोड़ा अधिक जटिल है, जो बैश के पार्सिंग-ऑर्डर और विशिष्टताओं पर अधिक निर्भर करता है। eval
लाइन मोटे तौर पर निम्न क्रम में आंतरिक रूप से पार्स जायेगा (ध्यान दें निम्नलिखित बयानों, स्यूडोकोड, नहीं वास्तविक कोड सिर्फ दिखाने के लिए कैसे बयान अंतिम परिणाम पर पहुंचने के लिए आंतरिक रूप से चरणों में टूट जायेगा प्रयास करने के लिए) ।
eval eval \$$keyA=\$$valA # substitution of $keyA and $valA by interpreter
eval eval \$keyB=\$valB # convert '$' + name-strings to real vars by eval
eval $keyB=$valB # substitution of $keyB and $valB by interpreter
eval that=amazing # execute string literal 'that=amazing' by eval
यदि मान लिया गया कि पार्सिंग आदेश यह स्पष्ट नहीं करता है कि eval पर्याप्त क्या कर रहा है, तो तीसरा उदाहरण अधिक स्पष्ट रूप से पार्सिंग का वर्णन करने में मदद कर सकता है कि क्या चल रहा है।
उदाहरण 4:
डिस्कवर करें कि क्या var, जिनके नाम तार में समाहित हैं, स्वयं में स्ट्रिंग मान हैं।
a="User-provided"
b="Another user-provided optional value"
c=""
myvarname_a="a"
myvarname_b="b"
myvarname_c="c"
for varname in "myvarname_a" "myvarname_b" "myvarname_c"; do
eval varval=\$$varname
if [ -z "$varval" ]; then
read -p "$varname? " $varname
fi
done
पहली यात्रा में:
varname="myvarname_a"
बैश तर्क को पार्स करता है eval
, और eval
रनटाइम में इसे सचमुच देखता है:
eval varval=\$$myvarname_a
निम्नलिखित छद्मकोड यह दर्शाने का प्रयास करता है कि कैसे वास्तविक कोड की उपरोक्त रेखा की व्याख्या की जाती है , जिसके द्वारा निष्पादित अंतिम मूल्य पर पहुंचने के लिए eval
। (निम्नलिखित लाइनें वर्णनात्मक हैं, सटीक बैश कोड नहीं):
1. eval varval="\$" + "$varname" # This substitution resolved in eval statement
2. .................. "$myvarname_a" # $myvarname_a previously resolved by for-loop
3. .................. "a" # ... to this value
4. eval "varval=$a" # This requires one more parsing step
5. eval varval="User-provided" # Final result of parsing (eval executes this)
एक बार सभी पार्सिंग हो जाने के बाद, परिणाम वही होता है जिसे निष्पादित किया जाता है, और इसका प्रभाव स्पष्ट होता है, यह प्रदर्शित करना कि विशेष रूप से eval
अपने बारे में कुछ भी रहस्यमय नहीं है, और जटिलता अपने तर्क की पार्सिंग में है।
varval="User-provided"
उपर्युक्त उदाहरण में शेष कोड यह देखने के लिए परीक्षण करता है कि क्या $ varval को दिया गया मान शून्य है, और यदि हां, तो उपयोगकर्ता को एक मूल्य प्रदान करने के लिए संकेत देता है।
$($n)
चलता$n
है। यह कमांड चलाने की कोशिश करता है1
जो मौजूद नहीं है।