Golang で filepath.Abs に ~(ホームディレクトリ) を指定した時にカレントワーキングディレクトリが先頭についてしまう
検証した環境は以下のとおりです。
$ go version go version go1.4.2 linux/amd64
$ whoami tkuchiki $ touch ~/testfile $ cd /tmp
した状態で、
// main.go package main import ( "fmt" "path/filepath" ) func main() { abspath, _ := filepath.Abs("~/testfile") fmt.Println(abspath) }
を実行してみたところ、
$ go run main.go /tmp/~/testfile
と出力されました。
カレントワーキングディレクトリが ~/
の前につくようですので、
/tmp/~
を実行ユーザのホームディレクトリに置換するようにしました。
追記1:
id:hnakamur3 さんからご指摘いただきました。
ありがとうございます。
http://golang.org/src/path/filepath/path.go?s=6548:6585#L223とhttp://golang.org/src/path/filepath/path_unix.go?s=313:341#L2 を見ると、
/で始まってなければIsAbs()がfalseになってAbs()でカレントディレクトリをくっつけるようになっています。
なので、Absを呼ぶ前に~をusr.HomeDirに置換するのが順当かなと思います。
確かにそのとおりですね。
あと、user.HomeDir
が絶対パスを返すので、
filepath.Abs() を実行しなくても、~
を user.HomeDir
で置換するだけで良さそうです。
// main2.go package main import ( "fmt" "os/user" "strings" ) func main() { usr, _ := user.Current() // usr.HomeDir = ホームディレクトリ f := strings.Replace("~/testfile", "~", usr.HomeDir, 1) fmt.Println(f) }
以下が実行結果です。
$ go run main2.go /home/tkuchiki/testfile
追記2:
mattn さんから、以下のように教えていただきました。
ありがとうございます。
@tkuchiki ないです。~/ は OS の表現でなくシェルの表現なので golang のコアからは提供してないです。
— mattn (@mattn_jp) 2015, 7月 31
@tkuchiki 実は以前に os.ExpandEnv("~/") か os.ExpandPath() 実装しようよ!って提案して却下されたのでした。
— mattn (@mattn_jp) 2015, 7月 31
~
はシェルで提供している機能なので、
Golang に実装されていなくてもおかしくないですね。
提案が却下されてしまったのは残念でした..
あまり調査していないので、
もっと簡単にやる方法があるかもしれません(あってほしい)。
修正前のコードを残しておきます。
// main2.go package main import ( "fmt" "os" "os/user" "path/filepath" "strings" ) func main() { wd, _ := os.Getwd() // カレントワーキングディレクトリ usr, _ := user.Current() abspath, _ := filepath.Abs("~/testfile") // usr.HomeDir = ホームディレクトリ f := strings.Replace(abspath, fmt.Sprintf("%s/~", wd), usr.HomeDir, 1) fmt.Println(f) }