Introducción: "¿Y dónde estoy?" — pregunta el programa
\nImagina: estás escribiendo una utilidad en Go que debe leer un archivo de configuración de una carpeta junto a su archivo ejecutable. O, por ejemplo, estás creando un archivo de registro en el mismo directorio donde se encuentra el programa. Parecería que podría ser más simple. Pero aquí comienza lo interesante: Go es un lenguaje compilado y tiene sus "secretos" cuando se trata de conocer su propia ubicación.
\nLa pregunta "How to get the directory of the currently running file?" es una de las más populares en Stack Overflow entre los principiantes en Go. Y no es casualidad. A diferencia de los lenguajes de scripting, donde __file__ (Python) o __dirname (Node.js) lo resuelven todo en un santiamén, en Go hay que pensar: ¿qué archivo nos interesa exactamente? El código fuente (durante la compilación) o el binario ejecutable (durante la ejecución).
En este artículo analizaremos ambos enfoques, aprenderemos a evitar las trampas típicas y escribiremos varios ejemplos de código en Go que se pueden usar en proyectos reales. ¡Allá vamos!
\n\nDos mundos, dos infancias: fuente vs binario
\nAntes de escribir código, comprendamos el dilema principal. En Go, el programa primero se compila en un binario estático. Cuando ejecutas go run main.go, Go crea un archivo ejecutable temporal y lo ejecuta. Cuando haces go build, obtienes un archivo listo que se puede transferir a otra computadora.
Por lo tanto, la pregunta "¿dónde estoy?" tiene dos respuestas:
\n- \n
- Ruta al archivo fuente — necesaria durante el desarrollo, para registro o pruebas. \n
- Ruta al archivo ejecutable — necesaria en producción, para encontrar recursos cercanos (configuraciones, bases de datos, etc.). \n
La mayoría de las respuestas en Stack Overflow se refieren a la segunda opción, pero cubriremos ambas para que estés completamente preparado.
\n\nMétodo n.º 1: Obtener el directorio del binario en ejecución
\nEste es el escenario más común. Tu programa ya está compilado y ejecutándose, y necesita saber desde qué carpeta se invocó. Go proporciona una forma elegante para esto: el paquete os y la función os.Executable().
Ejemplo de código: versión básica
\npackage main\n\nimport (\n "fmt"\n "os"\n "path/filepath"\n)\n\nfunc main() {\n // Obtenemos la ruta completa al archivo ejecutable\n exePath, err := os.Executable()\n if err != nil {\n fmt.Println("Error al obtener la ruta:", err)\n return\n }\n fmt.Println("Ruta completa al binario:", exePath)\n\n // Extraemos el directorio\n exeDir := filepath.Dir(exePath)\n fmt.Println("Directorio del archivo ejecutable:", exeDir)\n}\nEjecuta este código con go run main.go — verás una ruta como /tmp/go-build123456/b001/exe/main. Es un directorio temporal. Y si compilas (go build -o myapp) y ejecutas ./myapp, obtendrás la carpeta actual.
Trampas: enlaces simbólicos y chdir
\nLa función os.Executable() devuelve la ruta por la que se inició el programa. Pero hay matices:
- \n
- Enlaces simbólicos. Si ejecutaste el programa a través de un enlace simbólico (
/usr/local/bin/myapp -> /opt/myapp_v2/myapp),os.Executable()devolverá la ruta al enlace, no al archivo real. Para obtener la ruta "real", usafilepath.EvalSymlinks(). \n - Cambio del directorio de trabajo. Si el programa internamente llamó a
os.Chdir(), esto no afecta aos.Executable()— seguirá devolviendo la ruta al binario. \n
Versión mejorada con manejo de enlaces simbólicos
\npackage main\n\nimport (\n "fmt"\n "os"\n "path/filepath"\n)\n\nfunc main() {\n exePath, err := os.Executable()\n if err != nil {\n panic(err)\n }\n\n //