- Apresenta um truque para executar arquivos Go diretamente como se fossem executáveis
- Colocando
//usr/local/go/bin/go run "$0" "$@"; exit na primeira linha e dando permissão de execução, é possível rodar com ./script.go
- Esse método não é um shebang, e sim um uso do comportamento do POSIX de fazer fallback para o shell
/bin/sh quando ocorre ENOEXEC
- O shell executa a primeira linha como comando, enquanto o compilador Go a reconhece como comentário com
// e a ignora
- Com
"$0", passa-se o caminho do próprio arquivo, então o go run compila e executa o script, e "$@" repassa os argumentos
- A poderosa biblioteca padrão e a garantia de compatibilidade retroativa do Go o tornam adequado para scripting, e usando versões Go 1.x o script pode continuar funcionando por décadas
- É possível evitar a complexidade da gestão de dependências do Python, como ambientes virtuais e
pip/poetry/uv
Como funciona o shebang falso
- O shebang (
#!) especifica o interpretador via a syscall execve, mas a técnica apresentada neste texto não é um shebang
- O formato é colocar
//usr/local/go/bin/go run "$0" "$@"; exit na primeira linha do arquivo-fonte Go e, abaixo de package main, escrever código Go comum
- Dando permissão de execução com
chmod +x script.go, ele pode ser executado como ./script.go
- Verificando com
strace, quando o shell tenta executar ./script.go via execve, o kernel retorna ENOEXEC (Exec format error)
- Ao receber ENOEXEC, o shell faz fallback para
/bin/sh e interpreta o arquivo como script de shell
- No shell,
// não é comentário, e sim interpretado como caminho raiz (/), então //usr/local/go/bin/go é executado normalmente como caminho válido
- Assim, a primeira linha
//usr/local/go/bin/go run "$0" "$@"; exit é executada como comando pelo shell
"$0" passa o caminho do arquivo executado, então no comando de execução "$0" vira o caminho de script.go, e o go run localiza, compila e executa o próprio arquivo
"$@" é a expansão dos parâmetros posicionais a partir do primeiro argumento, permitindo chamadas como ./script.go -f flag0 here are some args
- Sem
; exit, o sh continuaria interpretando o arquivo Go linha por linha e acabaria gerando erro em tokens como package
Por que Go é adequado para scripting
- A garantia de compatibilidade retroativa do Go é o ponto central: usando Go 1.x, scripts escritos hoje continuam funcionando por muito tempo
- A biblioteca padrão bem desenvolvida e as ferramentas embutidas (formatador, linter etc.) são fornecidas sem configuração extra, o que maximiza o compartilhamento e a portabilidade dos scripts
- Diferentemente do Python, é possível executar o código sem precisar aprender sobre ambientes virtuais ou vários gerenciadores de pacotes (
pip, poetry, uv)
- Com as ferramentas embutidas do ecossistema Go e a integração com IDEs, dá para usar formatador e linter por padrão mesmo sem
.pyproject ou package.json
- Se o Go atual estiver instalado, ele pode ser executado em qualquer sistema operacional por décadas
Comparação com outras linguagens compiladas
- Rust tem compilação lenta, biblioteca padrão mais fraca, depende mais de bibliotecas externas e sua busca por perfeição tende a reduzir a velocidade de desenvolvimento
- Java e linguagens da JVM já contam com linguagens de script baseadas em bytecode da JVM, e scripting leve em Kotlin também pode ser uma alternativa
- Entre as linguagens compiladas, o Go tem características especialmente adequadas para uso como linguagem de script
Problema de formatação do gopls e solução
- O
gopls exige espaço após comentários (//example → // example), então a linha do shebang falso é quebrada
- Se houver espaço, vira
// usr/local/go/bin/go, e o shell deixa de reconhecer isso como caminho
- Solução: usar a sugestão da thread no HN de comentário de bloco
/**/ no lugar de //
- Escrever no formato
/*usr/local/go/bin/go run "$0" "$@"; exit; */
- O ponto e vírgula (
;) após exit é obrigatório
1 comentários
Comentários do Hacker News
A parte em que o autor diz “não quero me preocupar com pip vs poetry vs uv” na verdade é algo que o uv já atende diretamente para esse caso de uso
Incluindo as dependências do PyPI, basta ter a versão do Python e o uv instalados
Link para a documentação oficial do uv
#!/usr/bin/env -S uv run --python 3.14 --scriptAssim, mesmo que o próprio Python não esteja instalado, o uv baixa a versão especificada e executa
Quando alguém começa com Clojure, normalmente recebe a orientação de usar Leiningen, mas ao pesquisar Python aparecem venv, poetry, hatch, uv e várias outras opções
O uv está cada vez mais virando o padrão, mas ainda não é universal
Já tive a experiência de instalar Go com apt e depois reinstalar porque a versão era antiga demais, mas isso foi resolvido muito mais rápido
A questão dos ambientes virtuais no Python continua complexa
Uma ferramenta OSS escrita em Rust que gerencia automaticamente a versão do Python e o venv
Você configura apenas o
pyproject.tomle executapyflow main.py; ele instala e trava dependências como o Cargo, além de ajustar automaticamente a versão do Python para o projetoNa época, Poetry e Pipenv eram populares, mas ainda deixavam a desejar em venv e gerenciamento de versão
Uso principalmente
uv adde só recorro auv pipquando precisoMas o
uv pipainda herda as limitações do pip — a resolução de dependências muda conforme a ordem de instalaçãoInstalar
dep-acomuv pip install dep-ae depoisdep-b, inverter a ordem, ou instalar tudo de uma vez gera resultados diferentesIsso é mais um problema do pip, mas a confusão no gerenciamento de pacotes Python continua
O uv baixa tudo automaticamente
O Go recusou explicitamente suporte a shebang
Em vez disso, recomendam usar
gorunDá para executar com um truque POSIX como
/// 2>/dev/null ; gorun "$0" "$@" ; exit $?Nim, Zig e D permitem algo parecido com a opção
-run, e Swift, OCaml e Haskell conseguem executar o arquivo diretamenteLink para a discussão relacionada
go runyaegi GitHub
O texto dizendo “não quero saber a diferença entre pip, poetry e uv, só quero rodar o código” no fim das contas é um problema de familiaridade técnica
uv rune a PEP 723 já resolveram tudouv runaparecerUso Python há mais de 20 anos, mas sempre tive receio de qualquer codebase com pacotes externos ou venv
Graças ao
uv run, migrei todos os projetos da empresa, mas os pessoais já foram para GoNo longo prazo, prefiro linguagens com tipagem estática
O usuário só quer que o programa funcione
uv rune PEP 723 resolvem o problema, mas ainda existe barreira de entrada porque é preciso conhecer o uvEnquanto o uv não for a ferramenta padrão oficial, muita gente vai abandonar Python
Acho isso uma ideia realmente genial
Mas scripting exige uma noção de ergonomia diferente da de software para distribuição
bash é improvisado, Go é bom para produto, Python fica no meio do caminho, Ruby fica mais perto do bash, e Rust mais perto do Go
Scripts são úteis para combinar rapidamente comandos do sistema operacional e resolver tarefas pontuais
O Go não tem essa espontaneidade
No Debian, tentei rodar um app gtk simples com uv; as dependências estavam todas certas, mas ainda assim não funcionou e acabou em Core Dump
Toda vez que tento usar Python de novo, algo assim acontece
O Go é verboso, mas depois de compilar, simplesmente funciona
A questão central é conseguir terminar tudo em um único arquivo
Dá para fazer um script de 500 linhas em Go, mas a linguagem já parte da premissa de múltiplos arquivos e módulos
O fato de bang-line não funcionar também vem disso
Se de qualquer forma
go runcria um binário temporário, então me parece melhor simplesmente compilar e colocar em/usr/local/binbash também é apenas uma camada de abstração sobre o sistema, tanto quanto Python; só parece diferente por ser o shell padrão
Especialmente no sentido de tornar legível para humanos o código que a LLM gerou
Concordo que um usuário iniciante em Python não deveria precisar saber a diferença entre pip, poetry e uv
Mas um blogueiro escrevendo sobre esse tema pelo menos deveria saber que o uv resolve esse problema
Crítica ignorante não convence
Eu também não entendi completamente o conceito do uv, então fiquei curioso
Eu gosto de escrever scripts em Python
Dá para fazer coisas rápido e resolver tarefas simples sem se preocupar com tipos ou memória
Mas não quero usar isso em aplicações grandes
A maioria dos sistemas já vem com Python, e para scripts simples isso basta
Pensando que seria preciso instalar Go, eu ainda acharia melhor usar Python com uv
Como o próprio autor disse que “começou meio que trollando”, no fim a questão é só preferência por Go
Com
node bla.jsjá resolveÉ preciso saber o que a função retorna, e quando você conhece bem a linguagem, os tipos básicos viram memória muscular
Isso vale também para linguagens com tipagem estática
Se você está pensando nos outros, não deveria escrever código para distribuição em Python
Eu esperava uma crítica ao Python, mas no fim foi uma dica útil
Se a linguagem usa
//como comentário, dá para adaptar esse truqueFunciona com C/C++, Java, JavaScript, Rust, Swift, Kotlin, ObjC, D, F#, GLSL etc.
Em especial, é interessante para criar demos gráficas de arquivo único em GLSL
Exemplo no Shadertoy
Em C, também dá para usar comentário de bloco com algo como
/*/../usr/bin/env gcc "$0" "$@"; ./a.out; rm -vf a.out; exit; */É uma ideia parecida com o uv para Swift
Swift também tem suporte oficial a shebang
#!diretamenteNa época do TCC, eu usava isso como “scripting em C”
Em projetos grandes, a estrutura era um script de build ler o manifesto, compilar e executar depois
Mas controlar o ambiente é difícil, então isso não serve muito bem para uso profissional
Tem suporte direto a shebang
Se quiser uma linguagem com mais ergonomia, o .NET 10 também tem o recurso “run file directly”
Ele suporta shebang e instala pacotes automaticamente dentro do script
Com a diretiva
#:sdk, dá até para subir um web app na horaSó que a compilação AOT ainda está meio crua
No começo achei que seria uma crítica ao Python, mas acabou me fazendo pensar sobre a direção dos ecossistemas de linguagem
Acho que foi um grande erro o ML ter ficado preso ao Python
Porque é lento, o sistema de tipos é desconfortável e a distribuição é difícil
Agora é hora de considerar alternativas como TypeScript, Go e Rust
Mas a razão de ML ter escolhido Python foi a FFI baseada em C
NodeJS, Rust e Go são fracos nisso
Aí o Python leva vantagem
O ideal seria uma linguagem tão simples quanto Python, mas com sistema de tipos e modelo de distribuição melhores
Não quero trocar Python por uma linguagem saída do ecossistema JS
Lisp ou Lua (Torch) seriam opções melhores, mas Python venceu pela simplicidade
Eu mesmo estou desenvolvendo um framework de ML baseado em Lisp, mas acho difícil conseguir adoção
Problemas de compatibilidade de versão, ausência de semver, ecossistema instável e assim por diante fazem parecer que ele está atrás do JS
JS/Node amadureceu nos últimos 10 anos, mas Python ainda parece preso em 2012
É realmente uma pena que ML tenha se padronizado em Python
Ao criar ferramentas CLI, Go é muito mais rápido que Python
Acabei voltando para Python por causa da diferença de LOC, mas sinto falta do Go toda vez que executo
Talvez OCaml fosse o ideal, mas o tooling antiquado pesa
O problema de scripts em Go é que a primeira linha não pode ter espaço
Porque o
goplsforça formatação automáticaComo em CI também é importante manter consistência de formatação, isso importa na prática
Mas o problema maior é que não dá para usar go.mod
Ou seja, não dá para fixar versões de dependências, então a garantia de compatibilidade fica mais fraca