56207


以下のGo言語コードを`yellow.exe`という名前で保存していたとします

[code]

    package main
    
    import (
        "fmt"
    
        "github.com/fatih/color"
    )
    
    func main() {
        yellow := color.New(color.FgYellow).SprintFunc()
        fmt.Fprintf(color.Output, "< %s >\n", yellow("yellow"))
    }
    
[/code]

それを以下のようなコードで外部プログラム実行した場合、io.MultiWriter だと色が出力されません。

[code]

    package main
    
    import (
        "io"
        "os"
        "os/exec"
    )
    
    func main() {
        var cmd *exec.Cmd
    
        cmd = exec.Command(`yellow.exe`)
        cmd.Stdout = os.Stdout
        cmd.Run()
    
        cmd = exec.Command(`yellow.exe`)
        cmd.Stdout = io.MultiWriter(os.Stdout)
        cmd.Run()
    }
    
[/code]

この例では`os.Stdout`のみを`io.MultiWriter`に入れていますが、本来はファイルへの出力と同時に標準出力にも出力したいと考えていて、ファイルには色なしで出力し、標準出力には色付きで出力したいと考えています。また、外部プログラム実行をするプログラムはgo言語とは限らず、C#で作成したプログラムの場合もあり、外部プログラム側のコードはいじれない場合もあります。その場合にどのようにすれば、標準出力に色付きの出力をしつつ、ファイルにも同じ文字列を落とせるでしょうか？

========  
**追記(2018/07/10)**

@metropolis さんのコメントを受けて、さらなる調査を行ったところ、一定条件下での解決策は出たと思います。以下にそれを記しておきます。

`io.MultiWriter`を標準出力に設定すると、ターミナルではないという判定になり、`mattn/colorable`
が色設定をスキップするようなので、`fatih/color` 側の
`NoColor`をチェックし`true`ならエスケープ情報をそのまま標準出力に流し、親側に色情報を提供するようにしました。もし`false`なら生のターミナルにそのまま色情報を出力します。

[code]

    package main
    
    import (
        "fmt"
        "io"
        "os"
    
        "github.com/fatih/color"
    )
    
    func main() {
        c := color.New(color.FgYellow)
        var output io.Writer
        if color.NoColor {
            c.EnableColor()
            output = os.Stdout
        } else {
            output = color.Output
        }
        yellow := c.SprintFunc()
        fmt.Fprintf(output, "< %s >\n", yellow("yellow"))
    }
    
[/code]

親側はそれを受けて、標準出力は`colorable.NewColorable()`で受けて、ファイルへの出力は`colorable.NewNonColorable()`で受けてやることで、io.MultiWriterでも色設定をできるようにしました。

[code]

    package main
    
    import (
        "flag"
        "io"
        "os"
        "os/exec"
    
        colorable "github.com/mattn/go-colorable"
    )
    
    var c = flag.String("c", "yellow.exe", "")
    
    func main() {
        flag.Parse()
        var cmd *exec.Cmd
    
        cmd = exec.Command(*c)
        cmd.Stdout = colorable.NewColorable(os.Stdout)
        cmd.Run()
    
        f, _ := os.Create("yellow.txt")
        defer f.Close()
    
        cmd = exec.Command(*c)
        cmd.Stdout = io.MultiWriter(colorable.NewNonColorable(f), colorable.NewColorable(os.Stdout))
        cmd.Run()
    }
    
[/code]

`親子がGo言語で書ける` 且つ `子のコードを編集可能`
である場合に限り、この対応で問題ないと思いますが、これ以外の場合においては、いまだ解決策がない状態です。


CC BY-SA 4.0
2018-07-09T11:15:45.813
45451
2019-06-29T00:43:46.980
2018-07-10T13:00:04.780
18863
18863
question
windows go
色付き文字列をio.MultiWriterで出力するには


質問にある追記の通り、条件付きで色付き表示ができるようになりました。現状では条件以外の解決策はないと判断し、この質問自体は解決済みにマークさせていただきます。


CC BY-SA 4.0
2019-06-29T00:43:46.980
56207
2019-06-29T00:43:46.980
18863
45451
answer