Expand tilde to home directory

后端 未结 5 2232
北海茫月
北海茫月 2020-12-06 04:06

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 t

相关标签:
5条回答
  • 2020-12-06 04:19

    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").

    0 讨论(0)
  • 2020-12-06 04:20

    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))
    
    0 讨论(0)
  • 2020-12-06 04:36

    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.

    0 讨论(0)
  • 2020-12-06 04:40

    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).

    0 讨论(0)
  • 2020-12-06 04:44

    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.

    0 讨论(0)
提交回复
热议问题