How can I resolve symlinks in Go?
Currently I call readlink -f
but I want something more idiomatic.
package main
import (
"os/exec"
"fmt"
)
func resolve(p string) string {
cmd := exec.Command("readlink", "-f", p)
out, _ := cmd.Output()
return (string(out))
}
func main() {
fmt.Printf(resolve("/initrd.img"))
}
Unlike the embarrassing atrocity that is the windows variant, posix-style symbolic links operate on/in the filesystem layer itself. The only way to edit one would be to edit the filesystem directly -- and it's generally not worth it.
Yes. You can only stack so much symbolic links together before the kernel and/or application refuse to follow the chain.
In order to follow symbolic links, you must specify ls -L or provide a trailing slash. For example, ls -L /etc and ls /etc/ both display the files in the directory that the /etc symbolic link points to. Other shell commands that have differences due to symbolic links are du, find, pax, rm and tar.
A symlink is a symbolic Linux/ UNIX link that points to another file or folder on your computer, or a connected file system. This is similar to a Windows shortcut. Symlinks can take two forms: Soft links are similar to shortcuts, and can point to another file or directory in any file system.
See filepath.EvalSymlinks().
EvalSymlinks returns the path name after the evaluation of any symbolic links. If path is relative the result will be relative to the current directory, unless one of the components is an absolute symbolic link.
Tree:
/bin/sh -> bash
/usr/lib/libresolv.so -> ../../lib/libresolv.so.2
os.Readlink()
os.Readlink("/bin/sh") // => bash
os.Readlink("/usr/lib/libresolv.so") //=> ../../lib/libresolv.so.2
filepath.EvalSymlinks()
filepath.EvalSymlinks("/bin/sh") // => /bin/bash
filepath.EvalSymlinks("/usr/lib/libresolv.so") //=> /lib/libresolv-2.20.so
Note: not absolute path (cd /bin
)
filepath.EvalSymlinks("sh") // => bash
filepath.EvalSymlinks("/bin/sh") // => /bin/bash
And somthing more
filepath.EvalSymlinks("/bin/bash") // => /bin/bash
// but
os.Readlink("/bin/bash") // => error: readlink /bin/bash: invalid argument
Example application not for playground
Use os.Lstat:
func Lstat(name string) (fi FileInfo, err error)
Lstat returns a FileInfo describing the named file. If the file is a symbolic link, the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link. If there is an error, it will be of type *PathError.
EDIT:
Then returned os.FileInfo
will only allow you to check if 'name' is a link or not (fi.Mode() & os.ModeSymlink != 0
). If it is, then use os.Readlink to get the pointee:
func Readlink(name string) (string, error)
Readlink returns the destination of the named symbolic link. If there is an error, it will be of type *PathError.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With