{"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\/en\/2017\/05\/instalando-golang-no-linux\/","title":{"rendered":"Go on Ubuntu: installing and writing your first program"},"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>Note (2026):<\/strong> In 2017, this post covered installing Go 1.8.3 with <code>GOPATH<\/code> \u2014 a way of working that the language itself abandoned. We rewrote it as a <em>hello world<\/em> that actually runs on Ubuntu, with the current version and modules.<\/div>\n<p class=\"translation-block\">This is the shortest path from a clean Ubuntu installation to your first <strong>Go<\/strong> program running. It takes about ten minutes, and you end up with a single binary that runs on any Linux system \u2014 no interpreter, no virtual machine, no dependencies to install on the server.<\/p>\n<h2>Why Go, in two sentences<\/h2>\n<p>Go was designed at Google in 2007 because C++ took too long to compile and concurrency was too much work. The result: it compiles in seconds, has concurrency built into the language, and produces a <strong>static binary<\/strong>. That is why Docker, Kubernetes, Terraform, and Prometheus are written in it. The full story is in <a href=\"\/en\/2026\/09\/a-historia-da-linguagem-go\/\">The history of the Go language<\/a>.<\/p>\n<h2>Installing on Ubuntu<\/h2>\n<p>There are three options. The <strong>official tarball is recommended<\/strong> \u2014 the package from <code data-no-translation=\"\">apt<\/code> usually lags one or two versions behind, and that matters in Go because the language releases every six months.<\/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>Notice <code data-no-translation=\"\">rm -rf \/usr\/local\/go<\/code> before extracting: it is the step the official documentation requires and almost every tutorial forgets. Extracting over an old installation mixes files from two versions and produces errors that are hard to diagnose.<\/p>\n<p>Now for <code data-no-translation=\"\">PATH<\/code>. To apply it system-wide and make it work for new users:<\/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>If you see something like <code data-no-translation=\"\">go version go1.27.1 linux\/amd64<\/code>, you are ready. If the command was not found, the <code data-no-translation=\"\">source<\/code> above fixes it for the current session \u2014 in future sessions it loads automatically.<\/p>\n<p class=\"translation-block\">On an ARM machine, such as a Raspberry Pi, replace <code>linux-amd64<\/code> with <code>linux-arm64<\/code>.<\/p>\n<h3>The alternatives, and when to use them<\/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\"><code>apt<\/code> works if you only need to compile someone else's software and do not care about the version. For development, stick with the tarball.<\/p>\n<h2>Hello, world<\/h2>\n<p>Before setting up a project structure, look at the bare language. Create <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\"><code>go run<\/code> compiles and runs in memory without leaving a binary \u2014 it is the way to experiment. Three things to notice: every executable program starts with <code>package main<\/code>; the entry-point function is <code>func main()<\/code>; and an <code>import<\/code> is required and <strong>cannot be unused<\/strong>. If you import a package without using it, Go refuses to compile. It is deliberately strict.<\/p>\n<h2>Now the right way: a module<\/h2>\n<p>In practice, nobody works with standalone files. Go has organized projects into <strong>modules<\/strong> since version 1.11, and this is the change that retired the old <code data-no-translation=\"\">GOPATH<\/code> from this post in 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>This creates <code data-no-translation=\"\">go.mod<\/code>, which declares the module name and language version. Now for a slightly more interesting program \u2014 create <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>Here is the language's signature feature: <code data-no-translation=\"\">if err != nil<\/code>. Go has no exceptions \u2014 every function that can fail returns an error along with its result, and you must decide what to do with it. It is verbose, it is criticized, and it is intentional: the error path is visible in the code, not hidden in a <code data-no-translation=\"\">catch<\/code> far away.<\/p>\n<h2>Building the binary<\/h2>\n<p>This is the part that sells the language to server administrators:<\/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>The file <code data-no-translation=\"\">ola<\/code> is a complete executable. Copy it to another Linux system and it runs \u2014 no need to install Go there, or a runtime, or a library. You can also compile for another system without leaving your own:<\/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>Cross-compilation with one environment variable, no extra toolchain. That is why so many modern command-line tools are distributed as one binary per platform.<\/p>\n<h2>Using a dependency<\/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\">The <code>go.sum<\/code> file, created automatically, stores the hash of each dependency \u2014 ensuring that the version downloaded tomorrow is byte-for-byte identical to today's. <strong>Keep both files under version control<\/strong>, <code>go.mod<\/code> and <code>go.sum<\/code>, along with the code.<\/p>\n<h2>A taste of concurrency<\/h2>\n<p>You cannot introduce Go without showing the <em>goroutine<\/em>, which is why the language won over infrastructure:<\/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>The three sites are queried <strong>in parallel<\/strong>, and the total takes as long as the slowest, not the sum of all three. That takes one word \u2014 <code data-no-translation=\"\">go<\/code> \u2014 and one channel. No library, no thread pool, no <em>callback<\/em>.<\/p>\n<h2>The tools that come included<\/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\"><code>go fmt<\/code> deserves special mention: the language has <em>one<\/em> official style, enforced by a tool. From the outset, this ended the debate over tabs and braces that consumes time in other communities.<\/p>\n<h2>Multiple versions on the same machine<\/h2>\n<p>When a project is stuck on an older version, Go itself handles it \u2014 no external manager:<\/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>And since 1.21, there is something even better: if the <code data-no-translation=\"\">go.mod<\/code> for the project requires a version you do not have, <code data-no-translation=\"\">GOTOOLCHAIN<\/code> downloads the right one at build time, automatically.<\/p>\n<h2>Where to go next<\/h2>\n<ul>\n<li><strong><a href=\"https:\/\/go.dev\/tour\/\" target=\"_blank\" rel=\"noopener\">A Tour of Go<\/a><\/strong> \u2014 the official, interactive tutorial runs in your browser. It is the best starting point.<\/li>\n<li><strong><a href=\"https:\/\/go.dev\/doc\/effective_go\" target=\"_blank\" rel=\"noopener\">Effective Go<\/a><\/strong> \u2014 how to write code that looks like Go, not translated Java.<\/li>\n<li>Here on the blog: <a href=\"\/en\/2026\/09\/a-historia-da-linguagem-go\/\">The history of the Go language<\/a>, <a href=\"\/en\/2019\/12\/install-golang-linux\/\">the detailed installation howto<\/a> and <a href=\"\/en\/2017\/05\/linguagens-de-programacao\/\">the main programming languages<\/a>.<\/li>\n<li>Built in Go, for studying real code: <a href=\"\/en\/2026\/09\/go-postfixadmin\/\">go-postfixadmin<\/a> and <a href=\"\/en\/2017\/04\/instalando-gogs-no-ubuntu\/\">Gogs<\/a>.<\/li>\n<\/ul>\n<p>Ten minutes, a static binary, and a blue gopher. A good start.<\/p>","protected":false},"excerpt":{"rendered":"<p>This is the shortest path from a clean Ubuntu installation to your first running Go program. It takes about ten minutes, and by the end you will have a single binary that runs on any Linux machine \u2014 no interpreter, no \u2026 <a title=\"Go on Ubuntu: installing and writing your first program\" class=\"read-more\" href=\"https:\/\/www.linuxpro.com.br\/en\/2017\/05\/instalando-golang-no-linux\/\" aria-label=\"Read more about Go no Ubuntu: instalando e escrevendo seu primeiro programa\">Read more<\/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\/en\/wp-json\/wp\/v2\/posts\/122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/comments?post=122"}],"version-history":[{"count":6,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/122\/revisions"}],"predecessor-version":[{"id":1096,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/122\/revisions\/1096"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/media?parent=122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/categories?post=122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/tags?post=122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}