bash बैश में stderr और stdout रीडायरेक्ट




shell redirect (9)

here एक नज़र डालें। होना चाहिए:

yourcommand &>filename

( stdout और stderr दोनों को फ़ाइल नाम पर रीडायरेक्ट करता है)।

मैं एक प्रक्रिया के दोनों stdout और stderr दोनों को एक फ़ाइल में रीडायरेक्ट करना चाहता हूं। मैं बैश में ऐसा कैसे करूं?


# Close STDOUT file descriptor
exec 1<&-
# Close STDERR FD
exec 2<&-

# Open STDOUT as $LOG_FILE file for read and write.
exec 1<>$LOG_FILE

# Redirect STDERR to STDOUT
exec 2>&1

echo "This line will appear in $LOG_FILE, not 'on screen'"

अब, साधारण इको $ LOG_FILE को लिखेंगे। Deemonizing के लिए उपयोगी।

मूल पोस्ट के लेखक को,

यह निर्भर करता है कि आपको क्या हासिल करने की आवश्यकता है। यदि आपको केवल अपनी स्क्रिप्ट से कॉल करने वाले आदेश के अंदर / बाहर रीडायरेक्ट करने की आवश्यकता है, तो उत्तर पहले से ही दिए गए हैं। मेरा वर्तमान स्क्रिप्ट के भीतर रीडायरेक्ट करने के बारे में है जो उल्लिखित कोड स्निपेट के बाद सभी आदेश / अंतर्निर्मित (फोर्क शामिल है) को प्रभावित करता है।

एक और अच्छा समाधान दोनों std-err / out को रीडायरेक्ट करने और एक बार लॉगर या लॉग फ़ाइल करने के बारे में है जिसमें "स्ट्रीम" को दो में विभाजित करना शामिल है। यह कार्यक्षमता 'टीई' कमांड द्वारा प्रदान की जाती है जो कई फाइल डिस्क्रिप्टर (फाइल, सॉकेट, पाइप इत्यादि) को एक बार में लिख / जोड़ सकती है: टीई FILE1 FILE2 ...> (cmd1)> (cmd2) ...

exec 3>&1 4>&2 1> >(tee >(logger -i -t 'my_script_tag') >&3) 2> >(tee >(logger -i -t 'my_script_tag') >&4)
trap 'cleanup' INT QUIT TERM EXIT


get_pids_of_ppid() {
    local ppid="$1"

    RETVAL=''
    local pids=`ps x -o pid,ppid | awk "\\$2 == \\"$ppid\\" { print \\$1 }"`
    RETVAL="$pids"
}


# Needed to kill processes running in background
cleanup() {
    local current_pid element
    local pids=( "$$" )

    running_pids=("${pids[@]}")

    while :; do
        current_pid="${running_pids[0]}"
        [ -z "$current_pid" ] && break

        running_pids=("${running_pids[@]:1}")
        get_pids_of_ppid $current_pid
        local new_pids="$RETVAL"
        [ -z "$new_pids" ] && continue

        for element in $new_pids; do
            running_pids+=("$element")
            pids=("$element" "${pids[@]}")
        done
    done

    kill ${pids[@]} 2>/dev/null
}

तो, शुरुआत से। आइए मान लें कि हमारे पास टर्मिनल / dev / stdout (FD # 1) और / dev / stderr (FD # 2) से जुड़ा हुआ है। अभ्यास में, यह एक पाइप, सॉकेट या जो भी हो सकता है।

  • एफडी # 3 और # 4 बनाएं और क्रमशः # 1 और # 2 के समान "स्थान" को इंगित करें। एफडी # 1 बदलना अब से एफडी # 3 को प्रभावित नहीं करता है। अब, एफडी # 3 और # 4 क्रमशः एसटीडीओयूटी और एसटीडीईआरआर को इंगित करता है। इन्हें वास्तविक टर्मिनल एसटीडीओयूटी और एसटीडीईआरआर के रूप में उपयोग किया जाएगा।
  • 1>> (...) माता-पिता में आदेश देने के लिए STDOUT को पुनर्निर्देशित करता है
  • माता-पिता (सब-शैल) निष्पादन के STDOUT (पाइप) से 'टी' पढ़ते हैं और माता-पिता में उप-खोल में किसी अन्य पाइप के माध्यम से 'लॉगर' कमांड पर रीडायरेक्ट करते हैं। साथ ही यह एक ही इनपुट को एफडी # 3 (टर्मिनल) में कॉपी करता है
  • दूसरे भाग, बहुत समान, एसटीडीईआरआर और एफडी # 2 और # 4 के लिए एक ही चाल करने के बारे में है।

उपरोक्त रेखा वाले एक स्क्रिप्ट को चलाने का परिणाम और इसके अतिरिक्त यह एक:

echo "Will end up in STDOUT(terminal) and /var/log/messages"

...इस प्रकार है:

$ ./my_script
Will end up in STDOUT(terminal) and /var/log/messages

$ tail -n1 /var/log/messages
Sep 23 15:54:03 wks056 my_script_tag[11644]: Will end up in STDOUT(terminal) and /var/log/messages

अगर आप स्पष्ट तस्वीर देखना चाहते हैं, तो स्क्रिप्ट में इन 2 लाइनों को जोड़ें:

ls -l /proc/self/fd/
ps xf

bash your_script.sh 1>file.log 2>&1

1>file.log फ़ाइल file.log STDOUT भेजने के लिए खोल को file.log , और 2>&1 file.log (फ़ाइल डिस्क्रिप्टर 2) को STDOUT (फ़ाइल डिस्क्रिप्टर 1) पर रीडायरेक्ट करने के लिए कहता है।

नोट: आदेश liw.fi के रूप में मायने रखता है, 2>&1 1>file.log काम नहीं करता है।


उत्सुकता से, यह काम करता है:

yourcommand &> filename

लेकिन यह एक वाक्यविन्यास त्रुटि देता है:

yourcommand &>> filename
syntax error near unexpected token `>'

आपको इसका उपयोग करना होगा:

yourcommand 1>> filename 2>&1

LOG_FACILITY="local7.notice"
LOG_TOPIC="my-prog-name"
LOG_TOPIC_OUT="$LOG_TOPIC-out[$$]"
LOG_TOPIC_ERR="$LOG_TOPIC-err[$$]"

exec 3>&1 > >(tee -a /dev/fd/3 | logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_OUT" )
exec 2> >(logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_ERR" )

यह संबंधित है: syslog को stdOut और stderr लिखना।

यह लगभग काम करता है, लेकिन xinted से नहीं; (


Tcsh के लिए, मुझे निम्न आदेश का उपयोग करना होगा:

command >& file

यदि command &> file उपयोग करें, तो यह "अमान्य नल कमांड" त्रुटि देगा।


"सबसे आसान" तरीका (केवल bash4): ls * 2>&- 1>&-


मैं एक लॉग फ़ाइल और stderr में अभी भी कंसोल पर लिखा stdout प्लस stderr से उत्पादन करने के लिए एक समाधान चाहता था। तो मुझे टी के माध्यम से stderr आउटपुट डुप्लिकेट करने की जरूरत है।

यह समाधान मैंने पाया है:

command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
  • पहले स्वैप stderr और stdout
  • फिर लॉग फ़ाइल में stdout संलग्न करें
  • पाइप stderr टी करने के लिए और इसे लॉग फ़ाइल में भी संलग्न करें

आप stderr को stdout और stdout को फ़ाइल में रीडायरेक्ट कर सकते हैं:

some_command >file.log 2>&1 

here देखें

संपादित करें: टिप्पणियों में उल्लिखित आदेश को बदल दिया





pipe