{"id":122,"date":"2017-05-04T21:09:03","date_gmt":"2017-05-05T00:09:03","guid":{"rendered":"https:\/\/www.linuxpro.com.br\/2017\/05\/instalando-golang-no-linux\/"},"modified":"2026-09-08T03:38:31","modified_gmt":"2026-09-08T06:38:31","slug":"instalando-golang-no-linux","status":"publish","type":"post","link":"https:\/\/www.linuxpro.com.br\/es\/2017\/05\/instalando-golang-no-linux\/","title":{"rendered":"Go en Ubuntu: instalando y escribiendo tu primer programa"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" alt=\"Mascote do LinuxPro digitando no laptop com o primeiro programa compilando no terminal, ao lado do gopher do Go\" src=\"\/wp-content\/uploads\/2026\/09\/golang-v4.webp\" width=\"1052\" height=\"652\" \/><\/p>\n<div style=\"background:#fff8e1;border-left:4px solid #8b1a1a;padding:.8em 1em;margin:1em 0\" class=\"translation-block\"><strong>Nota (2026):<\/strong> Esta entrada era, en 2017, la instalaci\u00f3n de Go 1.8.3 con <code>GOPATH<\/code>, una forma de trabajar que el propio lenguaje abandon\u00f3. La reescribimos como un <em>hello world<\/em> de verdad en Ubuntu, con la versi\u00f3n actual y con m\u00f3dulos.<\/div>\n<p class=\"translation-block\">Este es el camino m\u00e1s corto entre un Ubuntu limpio y tu primer programa en <strong>Go<\/strong> funcionando. Lleva unos diez minutos, y al final sales con un binario \u00fanico que corre en cualquier Linux: sin int\u00e9rprete, sin m\u00e1quina virtual, sin dependencias que instalar en el servidor.<\/p>\n<h2>Por qu\u00e9 Go, en dos frases<\/h2>\n<p>Go fue dise\u00f1ado en Google en 2007 porque C++ tardaba demasiado en compilar y la concurrencia daba demasiado trabajo. El resultado: compila en segundos, tiene concurrencia incorporada en el lenguaje y ofrece un <strong>binario est\u00e1tico<\/strong>. Por eso Docker, Kubernetes, Terraform y Prometheus est\u00e1n escritos en \u00e9l. La historia completa est\u00e1 en <a href=\"\/es\/2026\/09\/a-historia-da-linguagem-go\/\">La historia del lenguaje Go<\/a>.<\/p>\n<h2>Instalaci\u00f3n en Ubuntu<\/h2>\n<p>Existen tres caminos. El <strong>tarball oficial es el recomendado<\/strong> \u2014 el paquete de <code data-no-translation=\"\">apt<\/code> suele quedarse una o dos versiones atr\u00e1s, y en Go eso importa porque el lenguaje lanza una versi\u00f3n cada seis meses.<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\"># descobre a vers\u00e3o atual sem abrir o navegador\nVER=$(curl -fsSL 'https:\/\/go.dev\/VERSION?m=text' | head -n1)\necho \"$VER\"\n\n# baixa e instala no lugar can\u00f4nico\ncd \/tmp\ncurl -fLO \"https:\/\/go.dev\/dl\/${VER}.linux-amd64.tar.gz\"\nsudo rm -rf \/usr\/local\/go\nsudo tar -C \/usr\/local -xzf \"${VER}.linux-amd64.tar.gz\"<\/code><\/pre>\n<p>F\u00edjate en el <code data-no-translation=\"\">rm -rf \/usr\/local\/go<\/code> antes de extraer: es el paso que la documentaci\u00f3n oficial exige y que casi todos los tutoriales olvidan. Extraer sobre una instalaci\u00f3n antigua mezcla archivos de dos versiones y genera un error dif\u00edcil de diagnosticar.<\/p>\n<p>Ahora el <code data-no-translation=\"\">PATH<\/code>. Para que tenga efecto en todo el sistema y sobreviva a nuevos usuarios:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">echo 'export PATH=$PATH:\/usr\/local\/go\/bin' | sudo tee \/etc\/profile.d\/go.sh\nsource \/etc\/profile.d\/go.sh\n\ngo version<\/code><\/pre>\n<p>Si ha aparecido algo como <code data-no-translation=\"\">go version go1.27.1 linux\/amd64<\/code>, est\u00e1 listo. Si el comando no se ha encontrado, el <code data-no-translation=\"\">source<\/code> anterior lo aplica en la sesi\u00f3n actual; en las pr\u00f3ximas se cargar\u00e1 solo.<\/p>\n<p class=\"translation-block\">En una m\u00e1quina ARM, como una Raspberry Pi, cambia <code>linux-amd64<\/code> por <code>linux-arm64<\/code>.<\/p>\n<h3>Las alternativas, y cu\u00e1ndo usarlas<\/h3>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\"># snap \u2014 vers\u00e3o recente, atualiza sozinho\nsudo snap install go --classic\n\n# apt \u2014 mais simples, vers\u00e3o mais velha\nsudo apt install golang-go<\/code><\/pre>\n<p class=\"translation-block\">El <code>apt<\/code> sirve si solo necesitas compilar algo de terceros y no te importa la versi\u00f3n. Para desarrollar, qu\u00e9date con el tarball.<\/p>\n<h2>Hello, world<\/h2>\n<p>Antes de cualquier estructura de proyecto, mira el lenguaje puro. Crea <code data-no-translation=\"\">ola.go<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-go\" data-no-translation=\"\">package main\n\nimport \"fmt\"\n\nfunc main() {\n    fmt.Println(\"Ol\u00e1, mundo!\")\n}<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go run ola.go<\/code><\/pre>\n<p class=\"translation-block\">El <code>go run<\/code> compila y ejecuta en memoria, sin dejar binario: es el modo de experimentar. Tres cosas a tener en cuenta: todo programa ejecutable empieza en <code>package main<\/code>; la funci\u00f3n de entrada es <code>func main()<\/code>; y el <code>import<\/code> es obligatorio y <strong>no puede sobrar<\/strong>. Si importas un paquete y no lo usas, Go se niega a compilar. Es r\u00edgido a prop\u00f3sito.<\/p>\n<h2>Ahora como es debido: un m\u00f3dulo<\/h2>\n<p>En la pr\u00e1ctica nadie trabaja con un archivo suelto. Go organiza los proyectos en <strong>m\u00f3dulos<\/strong> desde la versi\u00f3n 1.11, y ese es el cambio que jubil\u00f3 al viejo <code data-no-translation=\"\">GOPATH<\/code> de esta entrada en 2017:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">mkdir ~\/ola &amp;&amp; cd ~\/ola\ngo mod init exemplo.com\/ola<\/code><\/pre>\n<p>Esto crea el <code data-no-translation=\"\">go.mod<\/code>, que declara el nombre del m\u00f3dulo y la versi\u00f3n del lenguaje. Ahora un programa un poco m\u00e1s interesante \u2014 crea <code data-no-translation=\"\">main.go<\/code>:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-go\" data-no-translation=\"\">package main\n\nimport (\n    \"bufio\"\n    \"fmt\"\n    \"os\"\n    \"strings\"\n)\n\nfunc main() {\n    fmt.Print(\"Qual o seu nome? \")\n\n    leitor := bufio.NewReader(os.Stdin)\n    nome, err := leitor.ReadString('n')\n    if err != nil {\n        fmt.Fprintln(os.Stderr, \"erro ao ler a entrada:\", err)\n        os.Exit(1)\n    }\n\n    nome = strings.TrimSpace(nome)\n    if nome == \"\" {\n        fmt.Println(\"Voc\u00ea n\u00e3o digitou nada.\")\n        return\n    }\n\n    fmt.Printf(\"Ol\u00e1, %s! Bem-vindo ao Go.n\", nome)\n}<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go run .<\/code><\/pre>\n<p>Aqu\u00ed aparece la marca registrada del lenguaje: el <code data-no-translation=\"\">if err != nil<\/code>. En Go no existe la excepci\u00f3n \u2014 toda funci\u00f3n que puede fallar devuelve el error junto con el resultado, y est\u00e1s obligado a decidir qu\u00e9 hacer con \u00e9l. Es verboso, se critica, y es intencionado: el camino del error queda visible en el c\u00f3digo, no escondido en un <code data-no-translation=\"\">catch<\/code> lejos.<\/p>\n<h2>Generando el binario<\/h2>\n<p>Esta es la parte que vende el lenguaje a quien administra servidores:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go build -o ola\nls -lh ola\n.\/ola<\/code><\/pre>\n<p>El archivo <code data-no-translation=\"\">ola<\/code> es un ejecutable completo. C\u00f3pialo a otro Linux y funciona \u2014 no hace falta instalar Go all\u00ed, ni runtime, ni bibliotecas. Y se puede compilar para otro sistema sin salir del tuyo:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">GOOS=linux   GOARCH=arm64 go build -o ola-arm      # Raspberry Pi\nGOOS=windows GOARCH=amd64 go build -o ola.exe      # Windows\nGOOS=darwin  GOARCH=arm64 go build -o ola-mac      # Mac com Apple Silicon<\/code><\/pre>\n<p>Compilaci\u00f3n cruzada en una variable de entorno, sin toolchain extra. Por eso tantas herramientas de l\u00ednea de comandos modernas se distribuyen como un binario por plataforma.<\/p>\n<h2>Usando una dependencia<\/h2>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go get github.com\/fatih\/color<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-go\" data-no-translation=\"\">package main\n\nimport \"github.com\/fatih\/color\"\n\nfunc main() {\n    color.Green(\"Ol\u00e1, mundo!\")\n    color.New(color.FgYellow, color.Bold).Println(\"agora em amarelo e negrito\")\n}<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go mod tidy    # ajusta o go.mod: adiciona o que falta, remove o que sobra\ngo run .<\/code><\/pre>\n<p class=\"translation-block\">El <code>go.sum<\/code>, creado autom\u00e1ticamente, guarda el hash de cada dependencia: es lo que garantiza que la versi\u00f3n descargada ma\u00f1ana es byte a byte la misma de hoy. <strong>Versiona ambos archivos<\/strong>, <code>go.mod<\/code> y <code>go.sum<\/code>, junto con el c\u00f3digo.<\/p>\n<h2>Un adelanto de concurrencia<\/h2>\n<p>No se puede presentar Go sin mostrar la <em>goroutine<\/em>, que es el motivo por el que el lenguaje ha conquistado la infraestructura:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-go\" data-no-translation=\"\">package main\n\nimport (\n    \"fmt\"\n    \"net\/http\"\n    \"time\"\n)\n\nfunc checar(url string, resultado chan&lt;- string) {\n    inicio := time.Now()\n    resp, err := http.Get(url)\n    if err != nil {\n        resultado &lt;- fmt.Sprintf(\"%-28s ERRO: %v\", url, err)\n        return\n    }\n    defer resp.Body.Close()\n    resultado &lt;- fmt.Sprintf(\"%-28s %s em %v\", url, resp.Status, time.Since(inicio).Round(time.Millisecond))\n}\n\nfunc main() {\n    sites := []string{\n        \"https:\/\/www.linuxpro.com.br\",\n        \"https:\/\/go.dev\",\n        \"https:\/\/kernel.org\",\n    }\n\n    resultado := make(chan string)\n    for _, s := range sites {\n        go checar(s, resultado)     \/\/ dispara os tr\u00eas ao mesmo tempo\n    }\n\n    for range sites {\n        fmt.Println(&lt;-resultado)    \/\/ recebe conforme forem chegando\n    }\n}<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go run .<\/code><\/pre>\n<p>Los tres sitios se consultan <strong>en paralelo<\/strong>, y el total tarda lo que el m\u00e1s lento, no la suma de los tres. Esto es una palabra \u2014 <code data-no-translation=\"\">go<\/code> \u2014 y un canal. Sin biblioteca, sin pool de threads, sin <em>callback<\/em>.<\/p>\n<h2>Las herramientas que ya vienen incluidas<\/h2>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go fmt .\/...      # formata no padr\u00e3o oficial; n\u00e3o h\u00e1 debate de estilo em Go\ngo vet .\/...      # aponta erro prov\u00e1vel que compila mesmo assim\ngo test .\/...     # roda os testes\ngo doc fmt.Println   # documenta\u00e7\u00e3o sem sair do terminal\ngo clean -cache   # limpa o cache de build quando algo fica estranho<\/code><\/pre>\n<p class=\"translation-block\">El <code>go fmt<\/code> merece destaque: el lenguaje tiene <em>un<\/em> estilo oficial, aplicado por una herramienta. Esto zanj\u00f3, de ra\u00edz, la discusi\u00f3n sobre tabulaci\u00f3n y llaves que consume tiempo en otras comunidades.<\/p>\n<h2>Varias versiones en la misma m\u00e1quina<\/h2>\n<p>Cuando un proyecto est\u00e1 atascado en una versi\u00f3n antigua, el propio Go lo resuelve \u2014 sin gestor externo:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">go install golang.org\/dl\/go1.26@latest\ngo1.26 download\ngo1.26 version<\/code><\/pre>\n<p>Y, desde la 1.21, existe algo a\u00fan mejor: si el <code data-no-translation=\"\">go.mod<\/code> del proyecto pide una versi\u00f3n que no tienes, el <code data-no-translation=\"\">GOTOOLCHAIN<\/code> descarga la correcta en el momento del build, por s\u00ed solo.<\/p>\n<h2>Por d\u00f3nde seguir<\/h2>\n<ul>\n<li><strong><a href=\"https:\/\/go.dev\/tour\/\" target=\"_blank\" rel=\"noopener\">A Tour of Go<\/a><\/strong> \u2014 el tutorial oficial, interactivo, se ejecuta en el navegador. Es la mejor puerta de entrada.<\/li>\n<li><strong><a href=\"https:\/\/go.dev\/doc\/effective_go\" target=\"_blank\" rel=\"noopener\">Effective Go<\/a><\/strong> \u2014 c\u00f3mo escribir c\u00f3digo que parece Go, y no Java traducido.<\/li>\n<li>Aqu\u00ed en el blog: <a href=\"\/es\/2026\/09\/a-historia-da-linguagem-go\/\">La historia del lenguaje Go<\/a>, <a href=\"\/es\/2019\/12\/install-golang-linux\/\">el howto de instalaci\u00f3n detallado<\/a> e <a href=\"\/es\/2017\/05\/linguagens-de-programacao\/\">las principales lenguajes de programaci\u00f3n<\/a>.<\/li>\n<li>Hecho en Go, para estudiar c\u00f3digo real: <a href=\"\/es\/2026\/09\/go-postfixadmin\/\">go-postfixadmin<\/a> e <a href=\"\/es\/2017\/04\/instalando-gogs-no-ubuntu\/\">Gogs<\/a>.<\/li>\n<\/ul>\n<p>Diez minutos, un binario est\u00e1tico y un gopher azul. Buen comienzo.<\/p>","protected":false},"excerpt":{"rendered":"<p>Este \u00e9 o caminho mais curto entre um Ubuntu limpo e o seu primeiro programa em Go rodando. Leva uns dez minutos, e no fim voc\u00ea sai com um bin\u00e1rio \u00fanico que roda em qualquer Linux \u2014 sem interpretador, sem &#8230; <a title=\"Go en Ubuntu: instalando y escribiendo tu primer programa\" class=\"read-more\" href=\"https:\/\/www.linuxpro.com.br\/es\/2017\/05\/instalando-golang-no-linux\/\" aria-label=\"Leer m\u00e1s sobre Go no Ubuntu: instalando e escrevendo seu primeiro programa\">Leer m\u00e1s<\/a><\/p>","protected":false},"author":0,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3],"tags":[58,31,402,14,397,5],"class_list":["post-122","post","type-post","status-publish","format-standard","hentry","category-linux","category-ubuntu","tag-go","tag-golang","tag-gopher","tag-howto","tag-programacao","tag-ubuntu"],"_links":{"self":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/comments?post=122"}],"version-history":[{"count":6,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/122\/revisions"}],"predecessor-version":[{"id":1096,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/122\/revisions\/1096"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/media?parent=122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/categories?post=122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/tags?post=122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}