Path 将平铺展开到主目录
我有一个程序,它接受一个目标文件夹,文件将在其中创建。我的程序应该能够处理绝对路径和相对路径。我的问题是我不知道如何将Path 将平铺展开到主目录,path,go,Path,Go,我有一个程序,它接受一个目标文件夹,文件将在其中创建。我的程序应该能够处理绝对路径和相对路径。我的问题是我不知道如何将~扩展到主目录 import "path" import "os" // var destination *String is the user input func expandPath() { if path.IsAbs(*destination) { return } cwd, err :=
~
扩展到主目录
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)
}
我扩展目标的函数如下所示。如果给定的路径是绝对路径,则不会执行任何操作,否则它会将相对路径与当前工作目录联接
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)
}
因为它不展开~
,如果用户将~/Downloads
之类的内容作为目标传递,它就不起作用
我应该如何以跨平台的方式解决这个问题?通常,
~
在您的程序看到它之前由shell展开。调整程序从命令行以与shell扩展机制兼容的方式获取参数的方式 其中一个可能的问题是这样使用:
cmd := exec.Command("some-binary", someArg) // say 'someArg' is "~/foo"
它不会被扩展。例如,您可以改为使用:
cmd := exec.Command("sh", "-c", fmt.Sprintf("'some-binary %q'", someArg))
它将从shell中获得标准的~
扩展
编辑:修复了“sh-c”示例。Go提供了一个包,允许您获取当前用户,对于任何用户,都可以获取其主目录:
usr, _ := user.Current()
dir := usr.HomeDir
然后,使用将两个字符串组合到有效路径:
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:])
}
(请注意,user.Current()不是在go游乐场中实现的(可能是出于安全原因),因此我无法给出一个易于运行的示例)。一般来说,
~
在进入程序之前由shell进行扩展。但是有
一般来说是这样
我在我的一个程序中遇到了同样的问题,我所理解的是,如果我使用的标志格式是
--flag=~/myfile
,它就不会被扩展。但是如果运行--flag~/myfile
它将由shell展开(缺少=
,文件名显示为一个单独的“字”)。如果要展开tilde'~”以与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
而是通过系统调用(osx/linux)读取/etc/passwd
文件来确定主目录。在windows上,它使用OpenCurrentProcessToken
syscall来确定用户的主目录。我知道这是一个老问题,但现在有另一个选项。您可以使用将tidle扩展到用户的homedir:
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)
}
myPath := "~/.ssh"
fmt.Printf("path: %s; with expansion: %s", myPath, homedir.Expand(myPath))
谢谢,我不知道shell会这样做。@jnml,我想说格式字符串中的第一个单引号放错了位置,应该放在%q
占位符前面,以便读取fmt.Sprintf(“某个二进制“%q”,someArg)
@kostix:我不这么认为。在上面的示例中,从Sprintf返回的值应该是'some-binary”/home/login/foo“
。没有测试过,也许外部的单引号应该被删除。但是,在命令行中它们是正确的。@jml,是的,您是正确的:%q
本身生成一个带引号的字符串(我没有看到)。但我认为我最初的想法仍然成立:调用fmt.Sprintf
生成的任何字符串都将是一个参数,因此无需进一步引用它。如果您将路径作为CLI参数,但如果您从其他任何地方获得路径字符串,则不会。还要注意,shell支持~user/foo
,它也引用用户的主目录中的foo
。代码应为dir+“/”
,否则,结果将缺少一个/
而不是字符串。替换您可以使用filepath.Join(usr.HomeDir,path[2:])
来确保正确添加了目录分隔符。在Windows上,至少HomeDir没有以斜杠结尾。这个答案是99%正确的。但是if-strings.HasPrefix(path,“~/”)比if-path[:2]==“~/”
更准确。如果路径长度为零或一个字符,则后者将失败。路径“~”也没有正确处理——它还应该扩展到$HOME.Good catch;修正了,太棒了!感谢您提供了一个完整的示例(包括错误检查和所有!),但是您还需要导入“path/filepath”
,否则您的代码将无法工作。这比公认的答案或投票最多的答案更简单、更正确。