英文:
Expand tilde to home directory
问题
我有一个程序,它接受一个目标文件夹,文件将在其中创建。我的程序应该能够处理绝对路径和相对路径。我的问题是我不知道如何将~
扩展到主目录。
我的扩展目标的函数如下所示。如果给定的路径是绝对路径,则不执行任何操作,否则将相对路径与当前工作目录连接起来。
import "path"
import "os"
// var destination *String 是用户输入
func expandPath() {
if path.IsAbs(*destination) {
return
}
cwd, err := os.Getwd()
checkError(err)
*destination = path.Join(cwd, *destination)
}
由于path.Join
不会扩展~
,所以如果用户将~/Downloads
作为目标传递,它将无法工作。
我应该如何以跨平台的方式解决这个问题?
英文:
I have a program that accepts a destination folder where files will be created. My program should be able to handle absolute paths as well as relative paths. My problem is that I don't know how to expand ~
to the home directory.
My function to expand the destination looks like this. If the path given is absolute it does nothing otherwise it joins the relative path with the current working directory.
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)
}
Since path.Join
doesn't expand ~
it doesn't work if the user passes something like ~/Downloads
as the destination.
How should I solve this in a cross platform way?
答案1
得分: 106
Go提供了包os/user,它允许您获取当前用户以及任何用户的主目录:
usr, _ := user.Current()
dir := usr.HomeDir
然后,使用path/filepath将这两个字符串组合成有效的路径:
if path == "~" {
// 对于“~”,它不会被“else if”捕获
path = dir
} else if strings.HasPrefix(path, "~/") {
// 使用strings.HasPrefix,以便我们不会匹配像“/something/~/something/”这样的路径
path = filepath.Join(dir, path[2:])
}
(请注意,user.Current()在go playground中没有实现(可能是出于安全原因),因此我无法提供一个容易运行的示例)。
英文:
Go provides the package os/user, which allows you to get the current user, and for any user, their home directory:
usr, _ := user.Current()
dir := usr.HomeDir
Then, use path/filepath to combine both strings to a valid path:
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:])
}
(Note that user.Current() is not implemented in the go playground (likely for security reasons), so I can't give an easily runnable example).
答案2
得分: 23
一般来说,~
在你的程序之前会被你的shell展开。但是有一些限制。
一般来说,在Go中手动展开是不被推荐的。
我在我的一个程序中遇到了同样的问题,我所理解的是,如果我使用--flag=~/myfile
这样的标志格式,它不会被展开。但是如果你运行--flag ~/myfile
,它会被shell展开(=
符号缺失,文件名会作为一个单独的“单词”出现)。
英文:
In general the ~
is expanded by your shell before it gets to your program. But there are some limitations.
In general is ill-advised to do it manually in Go.
I had the same problem in a program of mine and what I have understood is that if I use the flag format as --flag=~/myfile
, it is not expanded. But if you run --flag ~/myfile
it is expanded by the shell (the =
is missing and the filename appears as a separate "word").
答案3
得分: 8
通常情况下,~
在你的程序看到之前会被shell展开。调整你的程序从命令行获取参数的方式,以与shell展开机制兼容。
可能的问题之一是像这样使用exec.Command:
cmd := exec.Command("some-binary", someArg) // 假设someArg是"~/foo"
这样不会被展开。你可以使用以下方式代替:
cmd := exec.Command("sh", "-c", fmt.Sprintf("'some-binary %q'", someArg))
这样将从shell中获得标准的~
展开。
编辑:修复了sh -c
的示例。
英文:
Normally, the ~
is expanded by the shell before your program sees it.
Adjust how your program acquires its arguments from the command line in a way compatible with the shell expansion mechanism.
One of the possible problems is using exec.Command like this:
cmd := exec.Command("some-binary", someArg) // say 'someArg' is "~/foo"
which will not get expanded. You can, for example use instead:
cmd := exec.Command("sh", "-c", fmt.Sprintf("'some-binary %q'", someArg))
which will get the standard ~
expansion from the shell.
EDIT: fixed the 'sh -c' example.
答案4
得分: 8
如果您正在使用exec.Command()
来扩展波浪线'~',您应该使用用户的本地shell进行扩展。
// 'sh','bash'和'zsh'都支持'-c'参数
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)上通过getpwuid_r
系统调用读取/etc/passwd
文件来确定主目录。在Windows上,它使用OpenCurrentProcessToken
系统调用来确定用户的主目录。
英文:
If you are expanding tilde '~' for use with exec.Command()
you should use the users local shell for expansion.
// '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)
}
However; when loading application config files such as ~./myrc
this solution is not acceptable. The following has worked well for me across multiple platforms
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
}
NOTE: usr.HomeDir
does not respect $HOME
instead determines the home directory by reading the /etc/passwd
file via the getpwuid_r
syscall on (osx/linux). On windows it uses the OpenCurrentProcessToken
syscall to determine the users home directory.
答案5
得分: 7
我知道这是一个旧问题,但现在有另一个选项。您可以使用go-homedir将波浪号扩展到用户的主目录:
myPath := "~/.ssh"
fmt.Printf("路径:%s;扩展后的路径:%s", myPath, homedir.Expand(myPath))
英文:
I know this is an old question but there is another option now. You can use go-homedir to expand the tidle to the user's homedir:
myPath := "~/.ssh"
fmt.Printf("path: %s; with expansion: %s", myPath, homedir.Expand(myPath))
答案6
得分: 0
这适用于 go >= 1.12:
if strings.HasPrefix(path, "~/") {
home, _ := os.UserHomeDir()
path = filepath.Join(home, path[2:])
}
英文:
This works on go >= 1.12:
if strings.HasPrefix(path, "~/") {
home, _ := os.UserHomeDir()
path = filepath.Join(home, path[2:])
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论