2012-01-16 27 views
84

Tôi đang viết một chương trình trong Go thực hiện một máy chủ như chương trình (cũng Go). Bây giờ tôi muốn có stdout của chương trình con trong cửa sổ terminal của tôi, nơi tôi bắt đầu chương trình cha mẹ. Một cách để làm điều này là với hàm cmd.Output(), nhưng điều này chỉ in ra giá trị sau khi quá trình đã thoát. (Đó là vấn đề vì chương trình giống như máy chủ này chạy trong một thời gian dài và tôi muốn đọc đầu ra nhật ký)Chuyển hướng đường ống dẫn xuất của quy trình con trong Go

Biến số outtype io.ReadCloser và tôi không biết mình nên làm gì với nó để đạt được nhiệm vụ của mình và tôi không thể tìm thấy bất kỳ thứ gì hữu ích trên web về chủ đề này.

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() 
} 

Giải thích vào mã: bỏ ghi chú các Println chức năng để lấy mã để biên dịch, tôi biết rằng Println(out io.ReadCloser) không phải là một chức năng có ý nghĩa.
(nó tạo ra đầu ra &{3 |0 <nil> 0}) Hai dòng này chỉ là bắt buộc để lấy mã để biên dịch.

+1

Dòng "exec" của câu lệnh nhập phải là "os/exec". – evilspacepirate

+0

cảm ơn cho thông tin, thực sự nó đã được chỉ exec trước go1, bây giờ của nó trong os. cập nhật nó cho go1 – mbert

+1

Tôi không nghĩ rằng bạn thực sự cần phải gọi 'io.Copy' trong thói quen đi – rmonjo

Trả lời

171

Bây giờ tôi muốn có stdout của chương trình con trong cửa sổ của thiết bị đầu cuối của tôi nơi tôi bắt đầu chương trình gốc.

Không cần phải gây rối với đường ống hoặc goroutines, điều này rất dễ dàng.

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() 
} 
+40

+1: Tôi muốn ví dụ này là trong tài liệu – tidwall

+3

Ngoài ra, nếu bạn muốn lệnh để nghe đầu vào, bạn có thể chỉ cần đặt 'cmd.Stdin = os.Stdin' do đó làm cho nó như thể bạn đã thực hiện nghĩa đen lệnh đó từ vỏ. – Nucleon

+1

Đã tiết kiệm rất nhiều thời gian và nỗi đau tiềm ẩn ở đây vì câu trả lời tuyệt vời của bạn. Cảm ơn bạn! – alphazero

16

Tôi tin rằng nếu bạn nhập ioos và thay thế này:

//fmt.Println(out) 

với điều này:

go io.Copy(os.Stdout, out) 

(xem tài liệu for io.Copyfor os.Stdout), nó sẽ làm những gì bạn muốn. (Tuyên bố miễn trừ trách nhiệm: không được kiểm tra.)

Bằng cách này, bạn có thể cũng muốn nắm bắt lỗi chuẩn, bằng cách sử dụng cùng một phương pháp như đối với đầu ra tiêu chuẩn, nhưng với cmd.StderrPipeos.Stderr.

+1

cảm ơn bạn, tôi đã không nhận ra rằng nó có thể được dễ dàng :) - đi là rất tốt (đọc c + + bài viết về vấn đề đó ...) – mbert

+0

@ mbert: Bạn đang chào đón! Xấu hổ, tôi phải thừa nhận rằng tôi chưa bao giờ thực sự sử dụng Go, nhưng vâng, nó có vẻ khá tuyệt vời. :-) – ruakh

+0

tại sao bạn biết điều này? bạn thực sự nên thử nó! – mbert

11

Đối với những người không cần điều này trong một vòng lặp, nhưng muốn đầu ra lệnh echo vào thiết bị đầu cuối mà không cần phải cmd.Wait() chặn báo cáo khác:

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") 
} 
+0

Minyi fyi: (Rõ ràng) bạn có thể bỏ lỡ kết quả của goroutines bắt đầu nếu "làm những thứ khác ở đây" hoàn thành nhanh hơn so với goroutines. Các() chính thoát sẽ gây ra các goroutines để kết thúc là tốt. vì vậy bạn có khả năng không kết thúc thực sự đầu ra để echo trong thiết bị đầu cuối nếu bạn không chờ đợi cho cmd để kết thúc. – galaktor

+0

Yup, điểm tốt. – elimisteve

Các vấn đề liên quan