गो में बच्चे की प्रक्रिया के रीडायरेक्ट पाइप को पुनर्निर्देशित करें


105

मैं Go में एक प्रोग्राम लिख रहा हूं जो प्रोग्राम (Go) जैसे सर्वर को निष्पादित करता है। अब मैं अपनी टर्मिनल विंडो में चाइल्ड प्रोग्राम का स्टैडआउट रखना चाहता हूं, जहां मैंने पैरेंट प्रोग्राम शुरू किया है। ऐसा करने का एक तरीका cmd.Output()फ़ंक्शन के साथ है , लेकिन यह प्रक्रिया समाप्त होने के बाद ही स्टडआउट प्रिंट करता है। (यह एक समस्या है क्योंकि यह सर्वर जैसा कार्यक्रम लंबे समय तक चलता है और मैं लॉग आउटपुट पढ़ना चाहता हूं)

चर outका है type io.ReadCloserऔर मुझे नहीं पता कि मुझे अपना कार्य प्राप्त करने के लिए इसके साथ क्या करना चाहिए, और मुझे इस विषय पर वेब पर कुछ भी उपयोगी नहीं मिल रहा है।

func main() {
    cmd := exec.Command("/path/to/my/child/program")
    out, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Println(err)
    }
    err = cmd.Start()
    if err != nil {
        fmt.Println(err)
    }
    //fmt.Println(out)
    cmd.Wait()
} 

कोड के लिए स्पष्टीकरण: Printlnकोड को संकलन करने के लिए फ़ंक्शन को अनइंस्टॉल करें , मुझे पता है कि Println(out io.ReadCloser)यह एक सार्थक फ़ंक्शन नहीं है।
(यह आउटपुट का उत्पादन करता है &{3 |0 <nil> 0}) इन दो लाइनों को केवल संकलन करने के लिए कोड की आवश्यकता होती है।


1
आयात विवरण की आपकी "निष्पादित" पंक्ति "ओएस / निष्पादन" होनी चाहिए।
बुराईपेसिपेट करें

इस जानकारी के लिए धन्यवाद, वास्तव में यह केवल पूर्व go1 निष्पादित किया गया था, अब इसकी ओएस में। go1 के लिए यह अद्यतन
mbert

1
मुझे नहीं लगता है कि आपको वास्तव io.Copyमें गो रूटीन के भीतर कॉल करने की आवश्यकता है
rmonjo

मुझे नहीं लगता कि आपको कॉल cmd.Wait()या for{}लूप की आवश्यकता है ... ये यहां क्यों हैं?
weberc2

@ weberc2 ने एलिमिस्टेव के उत्तर के लिए नीचे देखा। यदि आप केवल एक बार प्रोग्राम चलाना चाहते हैं, तो लूप के लिए आवश्यक नहीं है। लेकिन अगर आप cmd.Wait () को कॉल नहीं करते हैं, तो आपका मुख्य () आपके बुलाए गए प्रोग्राम के खत्म होने से पहले खत्म हो सकता है, और आपको वह आउटपुट नहीं मिलेगा जो आप चाहते हैं
mbert

जवाबों:


207

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

पाइप या गोरोइन के साथ गड़बड़ करने की आवश्यकता नहीं है, यह आसान है।

func main() {
    // Replace `ls` (and its arguments) with something more interesting
    cmd := exec.Command("ls", "-l")
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Run()
}

4
इसके अलावा, यदि आप चाहते हैं कि कमांड इनपुट के लिए सुने तो आप इसे केवल cmd.Stdin = os.Stdinइस तरह बना सकते हैं जैसे कि आपने अपने शेल से शाब्दिक रूप से उस कमांड को निष्पादित किया हो।
न्यूक्लियॉन

4
logस्टडआउट के बजाय पुनर्निर्देशन की तलाश करने वालों के लिए , यहां एक जवाब है
रिक स्मिथ

18

मुझे विश्वास है कि यदि आप आयात ioऔर osऔर इस की जगह:

//fmt.Println(out)

इसके साथ:

go io.Copy(os.Stdout, out)

(के लिएio.Copy और इसके लिएos.Stdout प्रलेखन देखें ), यह वही करेगा जो आप चाहते हैं। (अस्वीकरण: परीक्षण नहीं किया गया)

वैसे, आप शायद मानक-आउटपुट के लिए एक ही दृष्टिकोण का उपयोग करके, मानक-त्रुटि को पकड़ना चाहते हैं, लेकिन साथ cmd.StderrPipeऔर os.Stderr


2
@mbert: मैंने अन्य भाषाओं का पर्याप्त उपयोग किया था, और गो के बारे में पर्याप्त पढ़ा था, कि ऐसा करने के लिए क्या सुविधा मौजूद होगी, और लगभग किस रूप में; तब मुझे बस यह पुष्टि करने के लिए कि मेरे कूबड़ सही थे, और आवश्यक विवरण खोजने के लिए संबंधित पैकेज-डॉक्स (गूग्लिंग द्वारा पाया गया) को देखना था। सबसे कठिन भाग थे (1) यह खोजना कि मानक-आउटपुट किसे कहते हैं ( os.Stdout) और (2) इस आधार की पुष्टि करते हैं कि, यदि आप बिल्कुल नहीं बुलाते cmd.StdoutPipe()हैं, तो मानक-आउटपुट /dev/nullमूल-प्रक्रिया के मानक-आउटपुट के बजाय चला जाता है ।
बरखा

15

उन लोगों के लिए जिन्हें लूप में इसकी आवश्यकता नहीं है, लेकिन cmd.Wait()अन्य स्टेटमेंट्स को ब्लॉक किए बिना कमांड आउटपुट को टर्मिनल में गूंजना चाहेंगे :

package main

import (
    "fmt"
    "io"
    "log"
    "os"
    "os/exec"
)

func checkError(err error) {
    if err != nil {
        log.Fatalf("Error: %s", err)
    }
}

func main() {
    // Replace `ls` (and its arguments) with something more interesting
    cmd := exec.Command("ls", "-l")

    // Create stdout, stderr streams of type io.Reader
    stdout, err := cmd.StdoutPipe()
    checkError(err)
    stderr, err := cmd.StderrPipe()
    checkError(err)

    // Start command
    err = cmd.Start()
    checkError(err)

    // Don't let main() exit before our command has finished running
    defer cmd.Wait()  // Doesn't block

    // Non-blockingly echo command output to terminal
    go io.Copy(os.Stdout, stdout)
    go io.Copy(os.Stderr, stderr)

    // I love Go's trivial concurrency :-D
    fmt.Printf("Do other stuff here! No need to wait.\n\n")
}

माइनर फी: (जाहिर है) कि अगर आपका "यहाँ अन्य सामान करना" शुरू हो जाता है तो गोरोइनों की तुलना में तेजी से पूरा होने वाले गाउटइन के परिणाम याद आ सकते हैं। मुख्य () बाहर निकलने से गोरोइटिन भी समाप्त हो जाएंगे। इसलिए आप संभावित रूप से टर्मिनल में गूंज करने के लिए वास्तव में आउटपुट नहीं कर सकते हैं यदि आप सेमीड के खत्म होने का इंतजार नहीं करते हैं।
गलकटर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.