我有一个程序接受将创建文件的目标文件夹。我的程序应该能够处理绝对路径以及相对路径。我的问题是我不知道如何将~
扩展到主目录。
我扩展目的地的功能如下所示。如果给定的路径是绝对路径,则它什么都不做,否则它会将相对路径与当前工作目录连接起来。
import "path"
import "os"
// var destination *String is the user input
func expandPath() {
if path.IsAbs(*destination) {
return
}
cwd, err := os.Getwd()
checkError(err)
*destination = path.Join(cwd, *destination)
}
由于path.Join
没有展开~
,如果用户通过~/Downloads
之类的内容作为目的地,它就不起作用。
我应该如何以跨平台的方式解决这个问题?
答案 0 :(得分:64)
Go提供了包os/user,它允许您获取当前用户以及任何用户的主目录:
usr, _ := user.Current()
dir := usr.HomeDir
然后,使用path/filepath将两个字符串组合到一个有效路径:
if path == "~" {
// In case of "~", which won't be caught by the "else if"
path = dir
} else if strings.HasPrefix(path, "~/") {
// Use strings.HasPrefix so we don't match paths like
// "/something/~/something/"
path = filepath.Join(dir, path[2:])
}
(请注意,在go操场上没有实现user.Current()(可能出于安全考虑),所以我不能给出一个易于运行的例子。)
答案 1 :(得分:11)
一般情况下,{<1}}会在到达您的程序之前由您的shell 进行扩展。但有some limitations。
一般来说是ill-advised to do it manually in Go。
我在我的程序中遇到了同样的问题,我所理解的是,如果我将标志格式用作~
,则不会扩展。但是如果你运行--flag=~/myfile
它会被shell扩展(--flag ~/myfile
丢失,文件名显示为单独的&#34;字&#34;)。
答案 2 :(得分:6)
通常情况下,{<1}}会在程序看到之前由shell 扩展。
调整程序以与shell扩展机制兼容的方式从命令行获取其参数的方式。
可能的问题之一是使用exec.Command这样:
~
不会扩展。例如,您可以使用:
cmd := exec.Command("some-binary", someArg) // say 'someArg' is "~/foo"
将从shell获得标准cmd := exec.Command("sh", "-c", fmt.Sprintf("'some-binary %q'", someArg))
扩展。
编辑:修复'sh -c'示例。
答案 3 :(得分:5)
如果你正在扩展代字号&#39;〜&#39;与exec.Command()
一起使用时,您应该使用用户本地shell进行扩展。
// 'sh', 'bash' and 'zsh' all respect the '-c' argument
cmd := exec.Command(os.Getenv("SHELL"), "-c", "cat ~/.myrc")
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
然而;加载~./myrc
等应用程序配置文件时,此解决方案不可接受。以下在多个平台上对我来说效果很好
import "os/user"
import "path/filepath"
func expand(path string) (string, error) {
if len(path) == 0 || path[0] != '~' {
return path, nil
}
usr, err := user.Current()
if err != nil {
return "", err
}
return filepath.Join(usr.HomeDir, path[1:]), nil
}
注意: usr.HomeDir
不尊重$HOME
而是通过/etc/passwd
系统调用(osx)读取getpwuid_r
文件来确定主目录/ Linux的)。在Windows上,它使用OpenCurrentProcessToken
系统调用来确定用户主目录。
答案 4 :(得分:4)
我知道这是一个老问题,但现在还有另一种选择。您可以使用go-homedir将tidle扩展到用户的homedir:
myPath := "~/.ssh"
fmt.Printf("path: %s; with expansion: %s", myPath, homedir.Expand(myPath))