使用cli Go包读取外部文件

I'm using the cli Go package: https://github.com/codegangsta/cli

package main

import (
    "fmt"
    "github.com/codegangsta/cli"
    "io/ioutil"
    "os"
)

func main() {
    app := cli.NewApp()
    app.Name = "m2k"
    app.Usage = "convert markdown to kindle"
    app.Flags = []cli.Flag{
        cli.StringFlag{
            Name:  "file",
            Value: "english",
            Usage: "language for the greeting",
        },
    }

    app.Action = func(c *cli.Context) {
        file := "default"

        if len(c.Args()) > 0 {
            file = c.Args()[0]
        }

        //fmt.Println("file %s", file)
        fmt.Println("file %s", file)

        b, err := ioutil.ReadFile(file)
        if err != nil {
            panic(err)
        }

        err = ioutil.WriteFile("output.txt", b, 0644)
        if err != nil {
            panic(err)
        }
    }

    app.Run(os.Args)
}

I'm a Go beginner. So I probably did something very wrong.

I do this in the command line (I have a file called markdown.txt in the directory):

~/go/io$ go run io.go -file markdown.txt

But I get this error:

created by runtime.main /usr/lib/go/src/pkg/runtime/proc.c:221 exit status 2

EDIT:

I wrote fmt.Println("file %s", file) to app.Action but nothing is printed. Does this tell something about the problem?

cli.Context.Args returns args form the current context. Meaning, not the global arguments supplied. If you print the length of c.Args you'll see it is zero.

You can either use c.String("file") or remove the app.Flags, supply a command in the format of go run io.go path/to/file.txt and use c.Args.First()

Example:

package main

import (
    "github.com/codegangsta/cli"

    "io/ioutil"
    "log"
    "os"
    "strings"
)

func main() {
    app := cli.NewApp()
    app.Name = "m2k"
    app.Usage = "convert markdown to kindle"
    app.Action = mainAction
    app.Run(os.Args)
}

func mainAction(c *cli.Context) {
    var err error

    // use stdin/stdout by default
    in := os.Stdin
    out := os.Stdout
    defer out.Close()
    defer in.Close()

    // replace stdin if given
    if c.Args().First() != "" {
        in, err = os.Open(c.Args().First())
        if err != nil {
            log.Fatalln(err)
        }
        log.Printf("Using '%s' as source
", c.Args().First())
    }

    // replace stdout if given
    if c.Args().Get(1) != "" {
        out = os.NewFile(0666, c.Args().Get(1))
        log.Printf("Writing output to '%s'
", c.Args().Get(1))
    }

    b, err := ioutil.ReadAll(in)
    if err != nil {
        log.Fatalln(err)
    }

    out.Write([]byte(strings.Replace(string(b), "in", "out", 1)))
}

Result:

echo "in file content" > in.txt
go run foo.go in.txt
// 2015/02/17 11:49:49 Using 'in.txt' as source
// out file content