Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

resolve symlinks in Go

Tags:

symlink

go

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"))
}
like image 402
mnagel Avatar asked Aug 05 '13 15:08

mnagel


People also ask

Can you edit symlinks?

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.

Can you chain symlinks?

Yes. You can only stack so much symbolic links together before the kernel and/or application refuse to follow the chain.

Which command follows symlinks?

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.

What is the point of symlinks?

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.


2 Answers

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.

Examples

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

like image 123
Ivan Black Avatar answered Sep 20 '22 17:09

Ivan Black


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.

like image 32
zzzz Avatar answered Sep 18 '22 17:09

zzzz