import (
"fmt"
"log"
"os"
"path"
"path/filepath"
"runtime"
"strings"
)
func main() {
fmt.Println("GetCurrentAbsPath = ", GetCurrentAbsPath())
}
//
// `go run` 命令会将源代码编译到系统TEMP或TMP环境变量目录中然后动执行.
// 而 `go build` 只会在当前目录编译出可执行文件, 并不会自动执行.
//
// 所以在获取程序路径时要先判断当前程序是否在 TEMP/TMP 目录下:
//
// - 如果在, 说明当前程序是使用 `go run` 命令启动. 想要获取真实的路径就需要
// 使用 runtime.Caller 来获取.
//
// - 如果不在, 说明当前程序是用 `go build` 命令构建编译成可执行程序. 我们直
// 接使用 os.Executable 获取可执行程序所在目录即可.
//
func GetCurrentAbsPath() string {
dir := getCurrentAbsPathByExecutable()
tmpDir, _ := filepath.EvalSymlinks(os.TempDir())
if strings.Contains(dir, tmpDir) {
return getCurrentAbsPathByCaller()
}
return dir
}
//
// 获取当前执行文件绝对路径(`go build`)
//
// 如果是通过 `go build` 启动, 需要使用 os.Executable 获取可执行程序所在目录.
//
func getCurrentAbsPathByExecutable() string {
dir, err := os.Executable()
if err != nil {
log.Fatal(err)
}
dir, _ = filepath.EvalSymlinks(filepath.Dir(dir))
return dir
}
//
// 获取当前执行文件绝对路径(`go run`)
//
// 如果是通过 `go run` 启动, 需要使用 runtime.Caller 获取程序路径.
//
func getCurrentAbsPathByCaller() string {
if _, filename, _, ok := runtime.Caller(0); ok {
return path.Dir(filename)
}
return ""
}