किसी फ़ाइल में stdout को रीडायरेक्ट कैसे करें, और stdout + stderr को किसी दूसरे को कैसे भेजें?


32

मैं कैसे प्राप्त कर सकता हूं

cmd >> file1 2>&1 1>>file2

यही है, stdout और stderr को एक फ़ाइल (file1) पर पुनर्निर्देशित करना चाहिए और केवल stdout (file2) को दूसरे (दोनों परिशिष्ट मोड में) पर पुनर्निर्देशित करना चाहिए?

जवाबों:


41

समस्या यह है कि जब आप अपने आउटपुट को रीडायरेक्ट करते हैं, तो यह अगले रीडायरेक्ट के लिए उपलब्ध नहीं होता है। teeदूसरे पुनर्निर्देशन के लिए आउटपुट रखने के लिए आप एक सबशेल में पाइप कर सकते हैं :

( cmd | tee -a file2 ) >> file1 2>&1

या यदि आप टर्मिनल में आउटपुट देखना पसंद करते हैं:

( cmd | tee -a file2 ) 2>&1 | tee -a file1

पहले के stderr को जोड़ने से बचने के teeलिए file1, आपको अपनी कमांड के stderr को कुछ फ़ाइल डिस्क्रिप्टर (जैसे 3) में रीडायरेक्ट करना चाहिए, और बाद में इसे फिर से stdout में जोड़ें:

( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1

(साभार @ फ्रा-सान)


16

के साथ zsh:

cmd >& out+err.log > out.log

परिशिष्ट मोड में:

cmd >>& out+err.log >> out.log

में zsh, और बशर्ते mult_iosविकल्प को अक्षम नहीं किया गया है, जब एक फाइल डिस्क्रिप्टर (यहां 1) को लिखने के लिए कई बार पुनर्निर्देशित किया जाता है, तो शेल teeसभी लक्ष्यों के आउटपुट को डुप्लिकेट करने के लिए एक अंतर्निहित बनाता है।


मैं बाहर क्या समझ नहीं सकता out+errऔर outयहाँ मतलब है। फ़ाइल नाम? धाराओं को पुनर्निर्देशित किया जाना है?
ग्रोनोस्तज

@gronostaj सोचते हैं कि कमांड पढ़ता हैcmd >& file1 > file2
इसहाक

यह समाधान उस क्रम को संरक्षित करेगा जिसमें आउटपुट उत्पन्न किया गया था। वास्तव में stdout और stderr (उस क्रम में) को स्टोर करने के लिए आपको एक अलग दृष्टिकोण की आवश्यकता होती है।
इसहाक

1
@ इस्साक, आदेश को जरूरी संरक्षित नहीं किया जाएगा क्योंकि स्टडआउट आउटपुट एक पाइप के माध्यम से जाएगा (एक प्रक्रिया के लिए जो इसे प्रत्येक फ़ाइल के लिए अग्रेषित करता है) जबकि स्टडर आउटपुट सीधे फ़ाइल में जाएगा। किसी भी स्थिति में, यह ऐसा नहीं लगता है कि ओपी ने स्टैडर आउटपुट के बाद स्टडआउट के बाद आने के लिए कहा।
स्टीफन चेजालस

3

आप कर सकते हैं: टैग stdout (एक UNBUFFERED sed का उपयोग करते हुए, यानी:), sed -u ...stderr भी stdout (untagged के रूप में जाना जाता है, क्योंकि यह उस टैगिंग sed के माध्यम से नहीं गया था), और इस प्रकार परिणामी लॉगफ़ाइल में 2 को अलग करने में सक्षम हो।

निम्नलिखित: धीमा है (इसे गंभीरता से अनुकूलित किया जा सकता है, जबकि इसके बजाय एक पर्ल स्क्रिप्ट का उपयोग करने के लिए ..., करते हैं ...; किया; छूट के लिए, जो हर पंक्ति में सब-कमांड और कमांड को जन्म देगा!), अजीब। (ऐसा लगता है कि मुझे एक नाम बदलने वाले स्टैडआउट में 2 {} चरणों की आवश्यकता है और फिर दूसरे में "stderr" के माध्यम से "गिर गया" जोड़ें), लेकिन यह है: एक " अवधारणा का प्रमाण ", जो रखने की कोशिश करेगा आउटपुट का ऑर्डर जितना संभव हो उतना स्टडआउट और स्टेडर का सबसे अधिक:

#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch

#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
#  to see if the order of stdout&stderr is kept

#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2 
touch existing existing2 existing3

#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs... 
                     # avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.

{
   { for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
   } | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
    case "$line" in
       ${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;; 
        *)            printf "%s\n" "$line"       >> out_AND_err.file ;;   
    esac; 
done;

# see the results:
grep "^" out.file out_AND_err.file

यह समझना वास्तव में मुश्किल है। (१) ls unknownस्टादर पर कुछ छापने के लिए आप इस तरह के जटिल उपयोग मामले ( ) का उपयोग क्यों करते हैं ? >&2 echo "error"ठीक हो जाएगा। (2) teeएक ही बार में कई फ़ाइलों को जोड़ सकते हैं। (३) सिर्फ catइसके बजाय क्यों नहीं grep "^"? (4) आपकी स्क्रिप्ट तब विफल हो जाएगी जब stderr आउटपुट शुरू होता है _stdout_। (५) क्यों?
pLumo

@RoVo: पहली 2 टिप्पणी की गई रेखाएँ एल्गोरिथ्म को दिखाती हैं, अवधारणा उदाहरण के प्रमाण की तुलना में सरल। 1): यह ls loopदोनों आउटपुट और stderr पर, मिश्रित (वैकल्पिक रूप से), एक नियंत्रित क्रम में, ताकि हम जाँच कर सकें कि हम stderout के टैगिंग के बावजूद उस stderr / stdout आदेश को रखा जा सकता है): विष्णु पूंछ, हो सकता है, लेकिन नहीं नियमित पूंछ (पूर्व, ऐक्स पर।)। 3): grep "^" भी दोनों फाइलनाम को दर्शाता है। 4): इसे वेरिएबल द्वारा बदला जा सकता है। 5): पुरानी छूट (पुराने ऑक्स) पुरानी छूट पर काम करती है, जहां मैंने इसका परीक्षण किया (कोई भी उपलब्ध नहीं है)।
ओलिवियर दुलैक

(1) स्टेटर और स्टाउट के लिए कई गूंज ठीक होंगे, लेकिन ठीक है, महत्वपूर्ण नहीं, बस पढ़ना आसान होगा। (३) सहमत हैं, (४) निश्चित है, लेकिन यह विफल हो जाएगा यदि यह चर के साथ शुरू होता है। (५) मैं देखता हूं।
pLumo

@RoVo मैं आपके 1 से सहमत हूं)। 4) के लिए, चर को गायब करने के लिए आवश्यकतानुसार जटिल हो सकता है (उदा: uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406...)
ओलिवियर दुलैक

1
यकीन है, यह बहुत संभावना नहीं है, लेकिन वैसे भी यह बाद में एक सुरक्षा मुद्दे को पेश कर सकता है। और फिर आप फ़ाइल को प्रिंट करने से पहले उस स्ट्रिंग को निकालना चाह सकते हैं ;-)
pLumo

2

यदि उत्पादन का क्रम होना चाहिए: stdout तो stderr ; केवल पुनर्निर्देशन से कोई हल नहीं है।
Stderr को एक टेम्पोरल फ़ाइल में संग्रहित किया जाना चाहिए

cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err

विवरण:

एक आउटपुट (एक fd जैसे stdout या stderr) को दो फ़ाइलों पर पुनर्निर्देशित करने का एकमात्र तरीका इसे पुन: उत्पन्न करना है। teeफ़ाइल डिस्क्रिप्टर सामग्री को पुन: पेश करने के लिए कमांड सही उपकरण है। इसलिए, दो फ़ाइलों पर एक आउटपुट के लिए एक प्रारंभिक विचार का उपयोग करना होगा:

... |  tee file1 file2

कि दोनों फ़ाइलों (1 और 2) के लिए टी के स्टड पुन: पेश करता है टी के उत्पादन को अभी भी अप्रयुक्त छोड़ रहा है। लेकिन हमें (उपयोग -a) संलग्न करना होगा और केवल एक प्रति की आवश्यकता होगी। यह दोनों मुद्दों को हल:

... | tee -a file1 >>file2

teeStdout (दोहराने के लिए) के साथ आपूर्ति करने के लिए हमें सीधे कमांड से बाहर stderr का उपभोग करने की आवश्यकता है। एक तरीका है, यदि आदेश महत्वपूर्ण नहीं है (उत्पादन का क्रम होगा (सबसे शायद) उत्पन्न के रूप में संरक्षित किया जाएगा, जो भी आउटपुट पहले संग्रहीत किया जाएगा)। कोई एक:

  1. cmd 2>>file1 | tee -a file2 >>file1
  2. cmd 2>>file1 > >( tee -a file2 >>file1 )
  3. ( cmd | tee -a file2 ) >> file1 2>&1

विकल्प 2 केवल कुछ गोले में काम करता है। विकल्प 3 एक अतिरिक्त उपधारा (धीमी) का उपयोग करता है, लेकिन केवल एक बार फ़ाइल नामों का उपयोग करें।

लेकिन अगर stdout पहले होना चाहिए (जो भी ऑर्डर आउटपुट उत्पन्न होता है) हमें इसे अंतिम (पहला समाधान पोस्ट) में दर्ज करने के लिए स्टेंडर को स्टोर करने की आवश्यकता है।


1
या मेमोरी में स्टोर करें जैसे sponge:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
स्टीफन चेज़लस

1

विविधता के हितों में:

यदि आपका सिस्टम समर्थन करता है /dev/stderr, तो

(cmd | tee -a /dev/stderr) 2>> file1 >> file2

काम करेगा। के मानक आउटपुट cmd को स्टडआउट और पाइपलाइन के स्टैडर दोनों को भेजा जाता है। cmdबाईपास की मानक त्रुटिtee और पाइपलाइन के स्टैडर से बाहर आती है।

इसलिए

  • पाइपलाइन का स्टैडआउट केवल स्टैडआउट है cmd , और
  • पाइप लाइन का स्टेटरर cmdइंटरमिक्स होता है।

यह उन धाराओं को सही फाइलों में भेजने का एक साधारण मामला है।

इस तरह के लगभग किसी भी दृष्टिकोण के साथ ( स्टीफन के उत्तर सहित ), file1आदेश से बाहर लाइनें मिल सकती हैं।

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