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

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

在使用管道執行 go binary 時使用 scanln

在使用管道執行 go binary 時使用 scanln

Go
慕工程0101907 2022-01-17 10:11:50
我有以下代碼:package mainimport "fmt"func main() {    if scanln_test() {        fmt.Println("Success!")    }}func scanln_test() bool {    fmt.Print("Please type yes or no and then press enter [y/n]: ")    var response string    fmt.Scanln(&response)    if response == "y" {        return true    } else if response == "n" {        return false    } else {        return scanln_test()    }}通過管道執行編譯后的二進制文件時,例如:$ echo "just-showing-how-pipe-affects-the-behavior" | ./scanln我得到函數fmt.Print內部的無限輸出。scanln_test但是,當我不通過管道執行它時,一切正常。有沒有辦法解決這個問題?UPD。當使用管道執行二進制文件時,fmt.Scanln 返回“EOF”作為錯誤UPD2。上面帶有 echo 的示例只是為了說明管道,但我不想在我的 go 程序中閱讀此 echo 的內容。真實案例如下所示:wget -qO- http://example.com/get | sh -s "param". 我在這個下載的 shell 腳本中有執行 go 程序,我希望我的程序用 Y/N 向用戶顯示對話。我不確定這是否可能,所以現在我決定擺脫管道并像wget -qO- http://example.com/get | sh && go-program "param".
查看完整描述

2 回答

?
呼啦一陣風

TA貢獻1802條經驗 獲得超6個贊

因此,您需要來自 Stdin(管道)和用戶 Stdin(鍵盤)的并發輸入:

我認為您的答案是 cat 命令,請參閱:如何將初始輸入通過管道傳輸到進程中,然后該進程將是交互式的?

和:https://en.wikipedia.org/wiki/Cat_(Unix)


請參閱:如何在 Go 中通過管道傳輸多個命令?

并進行進程間通信


有 3 件事需要注意:

首先:檢查所有錯誤是一個好習慣:

在您的情況下:


n, err := fmt.Scanln(&response)  

第二:

您正在使用遞歸調用(Tail Call),這里沒有必要。

用簡單的 for 循環替換它并查看: Go

3 中的尾調用優化:

最后但并非最不重要的一點:如果輸入錯誤,您的代碼將永遠循環(如果編譯器無法優化尾調用,則消耗堆棧)!

最好限制在 3 個。

例如:


package main


import "fmt"

import "strings"


type Input int


const (

    Timeout Input = iota

    Yes

    No

    Abort

    BadInput

)


func userInput(msg string) Input {

    var input string

    for i := 0; i < 3; i++ {

        fmt.Println(msg)

        n, err := fmt.Scanln(&input)

        if n > 0 {

            switch strings.ToLower(input) {

            case "y":

                return Yes

            case "n":

                return No

            case "a":

                return Abort

            }

        }

        if err != nil {

            return BadInput // or panic(err)

        }

    }

    return Timeout

}

func main() {

    ans := userInput("Please type Yes,No or Abort and then press enter [y/n/a]: ")

    fmt.Println(ans)

    switch ans {

    case Yes:

        fmt.Println("Yes") // do some job

        //...

    }

}

編輯:使用這個簡單的“y/n”,您無需檢查它是否是管道。

即使是帶有一個字節切片的簡單 std Read 也很好:


os.Stdin.Read(b1)

查看我的管道示例:https ://stackoverflow.com/a/37334984/6169399


但如果您的標準輸入是管道,您可以使用:


bytes, err := ioutil.ReadAll(os.Stdin) 

一次讀取所有管道數據。但要小心處理錯誤。您可以檢查標準輸入是否與終端或管道相關聯,然后使用適當的代碼。

檢測它的簡單方法是否是管道:


package main


import (

    "fmt"

    "os"

)


func main() {

    info, err := os.Stdin.Stat()

    if err != nil {

        fmt.Println("not a pipe")

    } else {

        fmt.Println("pipe name=", info.Name(), "pipe size=", info.Size())

    }

}

全部在一個示例代碼中:


package main


import (

    "fmt"

    "io/ioutil"

    "os"

    "strings"

)


type Input int


const (

    Timeout Input = iota

    Yes

    No

    Abort

    BadInput

)


func userInput(msg string) Input {

    var input string

    for i := 0; i < 3; i++ {

        fmt.Println(msg)

        n, err := fmt.Scanln(&input)

        if n > 0 {

            switch strings.ToLower(input) {

            case "y":

                return Yes

            case "n":

                return No

            case "a":

                return Abort

            }

        }

        if err != nil {

            return BadInput // or panic(err)

        }

    }

    return Timeout

}

func main() {

    info, err := os.Stdin.Stat()

    if err != nil {

        //fmt.Println("not a pipe")

        ans := userInput("Please type Yes,No or Abort and then press enter [y/n/a]: ")

        fmt.Println(ans)

        switch ans {

        case Yes:

            fmt.Println("Yes") // do some job

            //...

        }


    } else {

        fmt.Println("pipe name=", info.Name(), "pipe size=", info.Size())

        bytes, err := ioutil.ReadAll(os.Stdin)

        fmt.Println(string(bytes), err) //do some jobe with bytes

    }


}



查看完整回答
反對 回復 2022-01-17
?
明月笑刀無情

TA貢獻1828條經驗 獲得超4個贊

您可以使用os.ModeCharDevice:


stat, _ := os.Stdin.Stat()


if (stat.Mode() & os.ModeCharDevice) == 0 {

    // piped

    input, _ := ioutil.ReadAll(os.Stdin)

} else {

    // not piped, do whatever, like fmt.Scanln()

}


查看完整回答
反對 回復 2022-01-17
  • 2 回答
  • 0 關注
  • 168 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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