goのos.Openは~を見てくれないっぽい。

~はだめ

os.Openは"~“をhome directoryとして空気を読んで良い感じに解釈してくれないっぽい。

// 01tilda.go
package main

import (
    "io"
    "log"
    "os"
)

func main() {
    filename := "~/.screenrc"
    f, err := os.Open(filename)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    io.Copy(os.Stdout, f)
}

ダメっぽい。

$ go run 01tilda.go
2017/06/01 08:47:59 open ~/.screenrc: no such file or directory
exit status 1

$HOMEもだめっぽい

$HOME も同様にダメっぽい

package main

import (
    "io"
    "log"
    "os"
)

func main() {
    filename := "$HOME/.screenrc"
    f, err := os.Open(filename)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    io.Copy(os.Stdout, f)
}
$ go run 02env.go
2017/06/01 08:51:04 open $HOME/.screenrc: no such file or directory
exit status 1

コマンドライン引数で渡された場合はshellが解釈してくれるので大丈夫

package main

import (
    "io"
    "log"
    "os"
)

func main() {
    filename := os.Args[1]
    f, err := os.Open(filename)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    io.Copy(os.Stdout, f)
}

こちらは大丈夫(対象が ~/.screenrc である理由はとくに無い)。

go run 03cmd.go ~/.screenrc
escape ^Jj
autodetach on
defscrollback 3000
vbell off
hardstatus alwayslastline "%{= rw} %H %{= wk}%-Lw%{= bw}%n%f* %t%{= wk}%+Lw %{= wk}%=%{= gk} %y/%m/%d %c "

というか

~$HOME もshellによって解釈されるものなのでos.Openに渡されるパスは変換後のパスを期待するという感じっぽい?

頑張って治さないといけないっぽい。

横着するなら、環境変数から$HOMEを取り出すだったり、os/userからHomeDirを取り出すだったりする。

gore version 0.2.6  :help for help
gore> :import os
gore> :import strings

gore> strings.Replace("~/.screenrc", "~", os.Getenv("HOME"), 1)
"/Users/podhmo/.screenrc"

gore> :import os/user
gore> u, _ := user.Current()
&user.User{
  Uid:      "501",
  Gid:      "20",
  Username: "podhmo",
  Name:     "podhmo",
  HomeDir:  "/Users/podhmo",
}
gore> strings.Replace("~/.screenrc", "~", u.HomeDir, 1)
"/Users/podhmo/.screenrc"

それかこの辺を使う。

github.com