亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

帶有修改后的 Stdin 的 exec.Wait() 無限期等待

帶有修改后的 Stdin 的 exec.Wait() 無限期等待

Go
心有法竹 2023-08-14 17:37:52
我在使用修改后的 Stdin 時遇到了 exec.Wait() 的奇怪行為。我只是修改 Stdin,以便能夠復制其內容、計算數據量……但這不是這里的問題。我制作這個精簡程序只是為了演示奇怪的行為:使用修改后的標準輸入,cmd.Wait()無限期地等待......直到我按“enter”或“^C”使用未經修改的標準輸入(取消注釋該行cmd.Stdin = os.Stdin),程序可以完美地處理到最后。當我用 Delve () 啟動這個程序(使用修改后的標準輸入)時dlv debug,程序完美地處理到最后!我還在和之間添加了time.Sleep30 秒,然后將程序附加到 Delve ( )。當我輸入 時,無限期地等待......直到我按“enter”或“^C”cmd.Start()cmd.Wait()dlv attach PIDcontinuecmd.Wait()我用 go1.11 和 go1.12 測試了這些行為package mainimport (    "fmt"    "os"    "os/exec")type Splitter struct {    f  *os.File    fd int}func NewSplitter(f *os.File) *Splitter {    return &Splitter{f, int(f.Fd())}}func (s *Splitter) Close() error {    return s.f.Close()}func (s *Splitter) Read(p []byte) (int, error) {    return s.f.Read(p)}func (s *Splitter) Write(p []byte) (int, error) {    return s.f.Write(p)}func main() {    var cmd *exec.Cmd    cmd = exec.Command("cat", "foobarfile")    cmd.Stdin = NewSplitter(os.Stdin)    //cmd.Stdin = os.Stdin    cmd.Stdout = NewSplitter(os.Stdout)    cmd.Stderr = NewSplitter(os.Stderr)    cmd.Start()    cmd.Wait()    fmt.Println("done")}我做錯了什么嗎?感謝您的幫助。
查看完整描述

2 回答

?
白豬掌柜的

TA貢獻1893條經驗 獲得超10個贊

該程序會按照您的要求復制內容。您也可以嘗試評論部分。這些評論是不言自明的,我希望它能解釋您的疑問。


package main


import (

    "io"

    "log"

    "os"

    "os/exec"

)


func main() {

    // Execute cat command w/ arguments

    // cmd := exec.Command("cat", "hello.txt")


    // Execute cat command w/o arguments

    cmd := exec.Command("cat")


    // Attach STDOUT stream

    stdout, err := cmd.StdoutPipe()

    if err != nil {

        log.Println(err)

    }


    // Attach STDIN stream

    stdin, err := cmd.StdinPipe()

    if err != nil {

        log.Println(err)

    }


    // Attach STDERR stream

    stderr, err := cmd.StderrPipe()

    if err != nil {

        log.Println(err)

    }


    // Spawn go-routine to copy os's stdin to command's stdin

    go io.Copy(stdin, os.Stdin)


    // Spawn go-routine to copy command's stdout to os's stdout

    go io.Copy(os.Stdout, stdout)


    // Spawn go-routine to copy command's stderr to os's stderr

    go io.Copy(os.Stderr, stderr)


    // Run() under the hood calls Start() and Wait()

    cmd.Run()


    // Note: The PIPES above will be closed automatically after Wait sees the command exit.

    // A caller need only call Close to force the pipe to close sooner.

    log.Println("Command complete")

}



查看完整回答
反對 回復 2023-08-14
?
精慕HU

TA貢獻1845條經驗 獲得超8個贊

您正在用其他 Go 類型替換進程文件描述符(通常為 )*os.File。為了讓 stdin 像流一樣工作,os/exec包需要啟動一個 goroutine 在io.Reader進程之間復制數據。這在os/exec包中記錄:

// Otherwise, during the execution of the command a separate

// goroutine reads from Stdin and delivers that data to the command

// over a pipe. In this case, Wait does not complete until the goroutine

// stops copying, either because it has reached the end of Stdin

// (EOF or a read error) or because writing to the pipe returned an error.

如果您查看程序的堆棧跟蹤,您會發現它正在等待 io goroutine 在以下位置完成Wait():


goroutine 1 [chan receive]:

os/exec.(*Cmd).Wait(0xc000076000, 0x0, 0x0)

? ? /usr/local/go/src/os/exec/exec.go:510 +0x125

main.main()

因為您現在可以控制數據流,所以您可以根據需要關閉它。如果這里不需要 Stdin,那么根本就不要分配它。如果要使用它,那么您必須Close()將其Wait()歸還。

另一種選擇是確保您使用的是*os.File,最簡單的方法是使用StdinPipe,StdoutPipeStderrPipe方法,后者又使用os.Pipe().?這種方式確保進程只處理*os.File,而不處理其他 Go 類型。


查看完整回答
反對 回復 2023-08-14
  • 2 回答
  • 0 關注
  • 194 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號