2012-05-22 14 views
7

मैंने कुछ जटिल स्क्रिप्ट्स के साथ लागू करने के लिए एक बैश लॉगिंग लाइब्रेरी लिखी है जिसे मेरी कंपनी वर्तमान में उपयोग कर रही है। मैं लॉग कॉल करते समय स्क्रिप्ट फ़ाइल नाम ($ {BASH_SOURCE}) और कॉलिंग स्क्रिप्ट के लाइन नंबर ($ {LINENO}) प्रदान करने पर डेडसेट कर रहा हूं। हालांकि, मैं पैरामीटर के रूप में इन दो चरों में पारित करने के लिए उपयोगकर्ता या स्क्रिप्ट को लागू करने पर भरोसा नहीं करना चाहता था। यदि यह सी/सी ++ था, तो मैं केवल एक मैक्रो बनाउंगा जो पैरामीटर सूची में "__FILE__" और "__LINE__" को पूर्ववत करता है।बैश पैरामीटर उद्धरण और eval

मैं अंततः इस भाग को काम करने में सक्षम था।

यहाँ प्रवेश पुस्तकालय है:

# log.sh 

LOG="eval _log \${BASH_SOURCE} \${LINENO}" 

_log() { 
    _BASH_SOURCE=`basename "${1}"` && shift 
    _LINENO=${1} && shift 

    echo "(${_BASH_SOURCE}:${_LINENO}) [email protected]" 
} 

और एक को लागू परीक्षण स्क्रिप्ट: यहाँ अवधारणा का एक सबूत के रूप में कुछ ज्यादा सरल सार हैं

# MyTest.sh 

. ./log.sh 

${LOG} "This is a log message" 
# (test.sh:5) This is a log message 

यह अच्छी तरह से बहुत से काम करता है (और, मैं इसे पहले काम करने के लिए रोमांचित था)। हालांकि, इसमें एक चमकदार समस्या है: उद्धरण और eval के बीच बातचीत। अगर मैं कॉल करता हूं:

${LOG} "I'm thrilled that I got this working" 
# ./test.sh: eval: line 5: unexected EOF while looking for matching `'' 
# ./test.sh: eval: line 6: syntax error: unexpected end of file 

अब, मुझे विश्वास है कि मैं समझता हूं कि यह क्यों हो रहा है। उद्धृत पैरामीटर को बरकरार रखा जाता है क्योंकि वे eval करने के लिए पारित कर रहे हैं, लेकिन उस बिंदु पर, सामग्री को परिणामस्वरूप कमांड स्ट्रिंग में रखा गया है। मुझे पता है कि मैं कुछ भागने से इसे ठीक कर सकता हूं; हालांकि, मैं वास्तव में कार्यान्वयन स्क्रिप्ट को ऐसा करने के लिए मजबूर नहीं करना चाहता हूं। इस "eval macro" क्षमता को लागू करने से पहले, मैंने उपयोगकर्ताओं को सीधे "_log" पर कॉल किया था और उन्हें वैकल्पिक रूप से "$ {LINENO} में पास करने की अनुमति दी थी।" इस कार्यान्वयन के साथ, उपरोक्त असफल कॉल (केवल उद्धृत वाक्य के साथ) ठीक काम करता है।

सबसे बुनियादी स्तर पर, सभी मैं वास्तव में चाहते हैं एक स्क्रिप्ट कॉल करने के लिए सक्षम होने के लिए के लिए है [लॉग ऑन समारोह/मैक्रो] "स्ट्रिंग विशेष characers साथ लॉग इन करने के" और जिसके परिणामस्वरूप लॉग संदेश है फ़ाइल नाम और लाइन को शामिल लॉग संदेश के बाद, कॉलिंग स्क्रिप्ट की संख्या। यदि यह संभव है, तो मुझे लगता है कि मैं बहुत करीब हूं, लेकिन अगर कुछ ऐसा है जो मुझे अनदेखा कर रहा है तो उसे एक अलग दृष्टिकोण की आवश्यकता होगी, मैं भी इसके लिए खुला हूं। मैं उपयोगकर्ताओं को उनके सभी संदेशों से बचने के लिए मजबूर नहीं कर सकता, क्योंकि इससे संभवतः वे इस पुस्तकालय का उपयोग नहीं कर पाएंगे। यह ऐसी समस्या है कि अगर मुझे इसका समाधान नहीं मिल रहा है, तो मैं संभवतः पुरानी क्षमता पर वापस आऊंगा (जिसकी आवश्यकता $ {LINENO} को फ़ंक्शन पैरामीटर के रूप में पारित करने की आवश्यकता है - यह बहुत कम घुसपैठ कर रहा था)।

टीएलडीआर: क्या उद्धृत पैरामीटर के भीतर विशेष वर्णों का सम्मान करने के लिए eval प्राप्त करने का कोई तरीका है, उन्हें बचने के बिना?

+0

यदि आप बैश विशिष्ट संरचनाओं का उपयोग कर रहे हैं, तो आपकी लॉगिंग स्क्रिप्ट को "log.sh" नहीं कहा जाना चाहिए। यह "log.bash" होना चाहिए। –

+0

@ विलियम पर्सेल - मैंने कुछ खोज की और शैल स्क्रिप्ट के नामकरण सम्मेलनों के संबंध में किसी भी प्रकार का मानक नहीं मिला। वास्तव में, ज्यादातर लोग पूरी तरह से एक प्रत्यय छोड़ने लगते हैं। ईमानदार होने के लिए मैंने कभी भी '\ *। Sh' (या, कोई विस्तार/प्रत्यय वाला स्क्रिप्ट) के अलावा कुछ भी नहीं देखा है। और सभी व्यावहारिकता में, इसका कोई प्रभाव नहीं होना चाहिए, है ना? दुभाषिया या तो स्क्रिप्ट की पहली पंक्ति से खींचा जाता है या आपका वर्तमान खोल उपयोग किया जाता है। ऐसा लगता है कि यह अनिवार्य रूप से व्यक्तिगत वरीयता के लिए नीचे आता है। लेकिन, शायद "\ *। Sh" किसी उपयोगकर्ता को इंगित कर सकता है कि स्क्रिप्ट "sh।" का उपयोग करती है – LousyG

+1

एकमात्र व्यावहारिक प्रभाव तब होगा जब कोई डेवलपर आपके कार्यों का एक अलग खोल के साथ उपयोग कर रहा हो। '* .sh' नाम के साथ, एक डेवलपर उचित रूप से मान लेगा कि आपकी लाइब्रेरी को zsh स्क्रिप्ट में सोर्स किया जा सकता है। –

उत्तर

12

यदि संभव हो तो eval से बचने की सलाह देते हैं। आपके लॉगिंग उपयोग के मामले के लिए, आप शैल बिल्टिन caller पर एक नज़र डाल सकते हैं। यदि आपको अधिक जानकारी चाहिए, तो आप BASH_SOURCE, BASH_LINENO और FUNCNAME चर का उपयोग कर सकते हैं। ध्यान दें कि ये सभी चर सरणी हैं और पूर्ण कॉल स्टैक हैं।

#! /bin/bash  

function log() { 
    echo "[$(caller)] $*" >&2 
    echo "BASH_SOURCE: ${BASH_SOURCE[*]}" 
    echo "BASH_LINENO: ${BASH_LINENO[*]}" 
    echo "FUNCNAME: ${FUNCNAME[*]}" 
} 

function foobar() { 
    log "failed:" "[email protected]" 
} 

foobar "[email protected]" 
+1

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

+1

बस एक नोट: यदि आप फ़ाइल नाम पर स्वरूपण पर नियंत्रण चाहते हैं: लाइन, आप एक सरणी असाइनमेंट में कॉलर का उपयोग कर सकते हैं और फ़ाइल नाम और लाइन का अलग-अलग उपयोग कर सकते हैं: स्थानीय fl = ($ (कॉलर)); echo "$ (त्रुटि [1]) में त्रुटि: $ (FL [0])" – Floyd

2

(नोट: इस के हवाले से की तत्काल समस्या का हल है, लेकिन कॉल स्टैक तक पहुँचने के बारे में @ nosid का जवाब बेहतर है)

बदलें _log की अपनी परिभाषा थोड़ा, पढ़ने के लिए निम्न उदाहरण देखें मानक के बजाय इनपुट स्थितीय मापदंडों से लॉग संदेश लेने से:

_log() { 
    # Set up _BASH_SOURCE and _LINENO the same way 

    cat <(echo -n "$(_BASH_SOURCE:$_LINENO) ") - 
} 

फिर एक यहाँ दस्तावेज़ या यहां स्ट्रिंग का उपयोग मानक इनपुट के माध्यम से अपने लॉग संदेश पारित:

${LOG} <<<"This is a log message" 
${LOG} <<<"I'm thrilled this works, too!" 
${LOG} <<HERE 
Even this long 
message works as 
intended! 
HERE 
+0

इनपुट के लिए धन्यवाद! मैं शायद नोसिड के समाधान के साथ जाऊंगा, क्योंकि मैं डेवलपर्स को "<<<" के रूप में महत्वहीन कुछ के बारे में शिकायत कर सकता हूं। लेकिन, यह जानना अच्छा लगता है कि कम प्रभाव के साथ एक समाधान उपलब्ध है, क्या मुझे इसकी आवश्यकता होनी चाहिए। – LousyG

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