POSIX शेल में `logger` को सभी आउटपुट कैसे भेजें?


10

मैं मानक आउटपुट और मानक त्रुटि को अलग से .xprofileउपयोग करने में लॉग इन करना चाहूंगा logger। बैश में मुझे लगता है कि कुछ इस तरह दिखेगा:

exec 1> >(logger --priority user.notice --tag $(basename $0)) \
     2> >(logger --priority user.error --tag $(basename $0))

मैं POSIX /bin/sh संगत तरीके से कैसे करूंगा ?

जवाबों:


10

कोई POSIX समकक्ष नहीं है। आप केवल एक पुनर्निर्देशन कर सकते हैं exec, कांटा नहीं। एक पाइप को एक कांटा की आवश्यकता होती है, और शेल बच्चे के खत्म होने का इंतजार करता है।

एक समाधान के लिए एक समारोह में अपने सभी कोड डाल रहा है।

all_my_code () {
  
}
{ all_my_code |
  logger --priority user.notice --tag "$(basename "$0")"; } 2>&1 | 
  logger --priority user.error --tag "$(basename "$0")"

(यह भी लकड़हारा के stdout उदाहरण से stderr उदाहरण के लिए किसी भी त्रुटि को लॉग करता है। आप अधिक फ़ाइल विवरणक फेरबदल के साथ इससे बच सकते हैं।)

यदि आप चाहते हैं कि loggerप्रक्रिया अभी भी चल रही है, तो भी मूल शेल बाहर निकलें , इनवोकेशन &के अंत में रखें logger

{ all_my_code |
  logger --priority user.notice --tag "$(basename "$0")" & } 2>&1 | 
  logger --priority user.error --tag "$(basename "$0")" &

वैकल्पिक रूप से, आप नामित पाइप का उपयोग कर सकते हैं।

pipe_dir=$(mktemp -d)
mkfifo "$pipe_dir/out" "$pipe_dir/err"
<"$pipe_dir/out" logger --priority user.notice --tag "$(basename "$0")" &
<"$pipe_dir/err" logger --priority user.error --tag "$(basename "$0")" &
exec >"$pipe_dir/out" 2>"$pipe_dir/err" 

rm -r "$pipe_dir"

यह संपूर्ण स्क्रिप्ट के लिए दो प्रविष्टियों (आउट एंड इर) के रूप में syslog में दिखाई देगा। प्रश्न में उदाहरण में प्रति कमांड एक (या दो) प्रविष्टि होगी।
डार्कहार्ट

@DarkHeart मुझे आपकी टिप्पणी समझ नहीं आ रही है। प्रश्न में कोड और मेरे द्वारा प्रस्तावित दोनों समाधान समान उदाहरणों की संख्या चलाते हैं loggerऔर उनमें से प्रत्येक के लिए समान इनपुट पास करते हैं।
गिल्स एसओ- बुराई को रोकें '

क्षमा करें, मेरी गलती
23 अक्टूबर को DarkHeart

1
यह सरल लगता है , इसलिए मैं आपके नामित पाइप समाधान के साथ जा रहा हूं।
l0b0

9

POSIX कमांड / प्रक्रिया प्रतिस्थापन


_log()( x=0
    while  [ -e "${TMPDIR:=/tmp}/$$.$((x+=1))" ]
    do     continue; done        &&
    mkfifo -- "$TMPDIR/$$.$x"    &&
    printf %s\\n "$TMPDIR/$$.$x" || exit
    exec >&- >/dev/null
    {  rm -- "$TMPDIR/$$.$x"
       logger --priority user."$1" --tag "${0##*/}"
    }  <"$TMPDIR/$$.$x" &
)   <&- </dev/null

आपको इसका उपयोग करने में सक्षम होना चाहिए जैसे:

exec >"$(_log notice)" 2>"$(_log error)"

यहाँ एक संस्करण है जो mktempकमांड का उपयोग करता है :

_log()( p=
    mkfifo "${p:=$(mktemp -u)}"    &&
    printf %s "$p"                 &&
    exec  <&- >&- <>/dev/null >&0  &&
    {   rm "$p"
        logger --priority user."$1" --tag "${0##*/}"
    }   <"$p" &
)

... जो बहुत कुछ करता है, सिवाय इसके कि यह mktempआपके लिए फ़ाइल नाम का चयन करने की अनुमति देता है। यह काम करता है क्योंकि प्रक्रिया प्रतिस्थापन जादुई नहीं है और प्रतिस्थापन की कमान करने के लिए एक समान तरीके से काम करता है । इसके स्थान पर कमांड रन वैल्यू के साथ विस्तार को बदलने के बजाय कमांड प्रतिस्थापन करता है, प्रक्रिया प्रतिस्थापन इसे एक फाइलसिस्टम लिंक के नाम से बदल देता है जहां आउटपुट पाया जा सकता है।

हालांकि POSIX खोल ऐसी चीज़ को प्रत्यक्ष रूप से प्रदान नहीं करता है, इसका अनुकरण करना बहुत सरलता से किया जाता है। आपको बस एक फ़ाइल बनाने की ज़रूरत है, उसके नाम को कमांड प्रतिस्थापन के मानक पर प्रिंट करें, और उसी के बैकग्राउंड में अपना कमांड चलाएं जो उस फ़ाइल पर आउटपुट करेगा। अब आप बस उस विस्तार के मूल्य में पुनर्निर्देशित कर सकते हैं - ठीक वैसे ही जैसे आप प्रक्रिया प्रतिस्थापन के साथ करते हैं। और इसलिए POSIX शेल आपको निश्चित रूप से आवश्यक सभी उपकरण प्रदान करता है - यह सब आवश्यक है कि आप उन्हें एक तरह से उपयोग करने के लिए डालते हैं जो आपको सूट करता है।

उपरोक्त दोनों संस्करण यह सुनिश्चित करते हैं कि वे अपने द्वारा बनाए गए उपयोग से पहले उनके द्वारा बनाए गए पाइपों के लिए फाइलसिस्टम लिंक को नष्ट कर दें। इसका मतलब है कि इस तथ्य के बाद कोई सफाई की आवश्यकता नहीं है, और, अधिक महत्वपूर्ण बात, उनकी धाराएं केवल उन प्रक्रियाओं के लिए उपलब्ध हैं जो शुरू में उन्हें खोलती हैं - और इसलिए उनके फाइलसिस्टम लिंक को आपकी लॉगिंग गतिविधि को स्नूप / हाइजैक करने के साधन के रूप में उपयोग नहीं किया जा सकता है। फाइलसिस्टम में अपने एफएस-लिंक को छोड़ने के लिए एक संभावित सुरक्षा छेद है।


दूसरा तरीका यह है कि इसे लपेटें। इसे स्क्रिप्ट के भीतर से किया जा सकता है।

x=${x##*[!0-9]*}
_log(){ 
    logger --priority user."$1" --tag "${0##*/}"
}   2>/dev/null >&2

cd ../"$PPID.$x" 2>/dev/null &&
trap 'rm -rf -- "${TMPDIR:-/tmp}/$PPID.$x"' 0 || 
{   until cd -- "${TMPDIR:=/tmp}/$$.$x"
    do    mkdir -- "$TMPDIR/$$.$((x+=1))"
    done  && 
    x=$x "$0" "$@" | _log notice
    exit
}   2>&1 | _log error

यह मूल रूप से आपकी स्क्रिप्ट को स्वयं को कॉल करने की अनुमति देगा यदि यह अभी तक नहीं है और आपको टेम्प में बूट करने के लिए कार्य निर्देशिका मिल सकती है।


1
हो गया , धन्यवाद!
l0b0

@ l0b0 - मैं बस इस तरह का एक और अपडेट करने वाला हूं ... यह अधिक सामान्य है, और मैं अंत में इसे कुछ विकल्पों को संभालने की क्षमता देने के लिए चारों ओर हो गया, जैसे कि i / o डिस्क्रिप्टर / फाइलों से संबंधित हैं।
मिकसर्व

@ l0b0 - यदि आप mktempअन्य गैर-मानक कमांड का उपयोग करना चाहते हैं , तो यह हो सकता है _log()( p=; mkfifo "${p:=$(mktemp -u)}"; printf %s "$p"; exec <&- >&- <>/dev/null >&0; { rm "$p"; logger --priority user."$1" --tag "${0##*/}"; } <"$p" &):। मैंने इसे पूरी तरह से पोर्टेबल कमांड भाषा का उपयोग करके सभी तरीकों से लिखा - अपने खुद के अपवाद के साथ। इसके अलावा, basenameबहुत उपयोगी उपयोगिता नहीं है। "${0##*/}"अधिक मजबूत और तेज दोनों है।
मोकेसर

मैंने इसे बदल दिया क्योंकि मुझे केवल आधुनिक प्लेटफार्मों पर काम करने की आवश्यकता है; मुख्य मुद्दा यह था कि .xprofile इसके साथ निष्पादित किया जाना था sh
l0b0

1
@Wildcard - बस एक मिनट और मैं सवाल के पहले भाग को हल करने की कोशिश करूंगा, लेकिन दूसरे का जवाब हां में है: किनारे का मामला zshw / multios सक्षम है। पहले भाग के लिए के रूप में: { this; can\'t; happen; before; } < this। क्या उससे मदद हुई?
रात 15:53
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.