- Memperkenalkan trik untuk menjalankan file Go langsung seperti executable
- Jika menaruh
//usr/local/go/bin/go run "$0" "$@"; exit di baris pertama dan memberi izin eksekusi, file dapat dijalankan dengan ./script.go
- Cara ini bukan shebang, melainkan memanfaatkan perilaku fallback POSIX ke /bin/sh saat ENOEXEC terjadi
- Shell mengeksekusi baris pertama sebagai perintah, sementara kompiler Go mengenalinya sebagai komentar
// dan mengabaikannya
- Dengan
"$0" path dirinya sendiri diteruskan sehingga go run membangun dan menjalankan skrip tersebut, dan $@ meneruskan argumen
- Pustaka standar Go yang kuat dan jaminan kompatibilitas mundur membuatnya cocok untuk scripting; selama memakai Go 1.x, skrip dapat tetap berjalan selama puluhan tahun
- Dapat menghindari kerumitan manajemen dependensi seperti virtual environment Python, pip/poetry/uv, dan sejenisnya
Cara kerja shebang palsu
- shebang (
#!) menentukan interpreter melalui system call execve, tetapi teknik yang diperkenalkan di tulisan ini bukan shebang
- Baris pertama file sumber Go diisi dengan
//usr/local/go/bin/go run "$0" "$@"; exit, lalu di bawah package main diletakkan kode Go biasa
- Setelah memberi izin eksekusi dengan
chmod +x script.go, file bisa dijalankan seperti ./script.go
- Jika diperiksa dengan
strace, saat shell mencoba menjalankan ./script.go lewat execve, kernel mengembalikan ENOEXEC (Exec format error)
- Shell yang menerima ENOEXEC lalu fallback ke
/bin/sh untuk menafsirkan file tersebut sebagai shell script
- Di shell,
// bukan komentar melainkan ditafsirkan sebagai path root (/), sehingga //usr/local/go/bin/go tetap merupakan path yang valid
- Karena itu, baris pertama
//usr/local/go/bin/go run "$0" "$@"; exit dijalankan sebagai perintah oleh shell
"$0" meneruskan path file yang dieksekusi, jadi dalam perintah tersebut "$0" menjadi path script.go, dan go run pun menemukan, membangun, lalu menjalankan dirinya sendiri
"$@" adalah ekspansi positional parameter mulai dari argumen pertama, sehingga pemanggilan seperti ./script.go -f flag0 here are some args bisa dilakukan
- Tanpa
; exit, sh akan terus menafsirkan file Go baris demi baris lalu gagal saat menemui token seperti package
Mengapa Go cocok untuk scripting
- Jaminan kompatibilitas mundur Go adalah fitur kunci, sehingga selama memakai Go 1.x, skrip yang ditulis bisa berjalan dalam jangka panjang
- Pustaka standar yang matang dan tool bawaan (formatter, linter, dll.) tersedia tanpa konfigurasi tambahan, sehingga berbagi skrip dan portabilitas menjadi maksimal
- Berbeda dengan Python, Anda tidak perlu mempelajari virtual environment atau berbagai package manager seperti pip, poetry, uv hanya untuk menjalankan kode
- Dengan tool bawaan ekosistem Go dan integrasi IDE, formatter dan linter dapat dipakai secara default tanpa
.pyproject atau package.json
- Selama Go versi modern terpasang, skrip dapat berjalan di OS mana pun selama puluhan tahun
Perbandingan dengan bahasa terkompilasi lain
- Rust memiliki waktu kompilasi yang lambat dan pustaka standar yang lebih lemah sehingga penggunaan dependensi nyaris wajib, serta tuntutan kesempurnaan yang memperlambat pengembangan
- Java dan bahasa JVM sudah memiliki bahasa scripting berbasis bytecode JVM, dan lightweight Kotlin scripting juga bisa menjadi alternatif
- Di antara bahasa terkompilasi, Go memiliki karakteristik yang paling cocok untuk kebutuhan scripting
Masalah formatting gopls dan solusinya
gopls mewajibkan spasi setelah komentar (//example → // example), sehingga baris shebang palsu menjadi rusak
- Jika ada spasi,
// usr/local/go/bin/go tidak lagi dikenali shell sebagai path
- Solusi: gunakan saran dari thread HN ini, yaitu komentar blok
/**/ alih-alih //
- Tulis dalam bentuk
/*usr/local/go/bin/go run "$0" "$@"; exit; */
- Titik koma (
;) setelah exit wajib ada
1 komentar
Komentar Hacker News
Bagian “tidak peduli soal pip vs poetry vs uv” yang disebut penulis sebenarnya didukung langsung oleh uv
Termasuk dependensi PyPI, asalkan versi Python dan uv terpasang, itu sudah cukup
Tautan dokumentasi resmi uv
#!/usr/bin/env -S uv run --python 3.14 --scriptDengan begini, meskipun Python sendiri tidak terpasang, uv akan mengunduh versi yang ditentukan lalu menjalankannya
Saat pertama kali mencoba Clojure, kebanyakan orang disarankan memakai Leiningen, tetapi kalau mencari Python, yang muncul justru venv, poetry, hatch, uv, dan banyak lagi
uv memang makin menjadi arus utama, tetapi belum benar-benar universal
Saya pernah memasang Go lewat apt lalu harus memasangnya ulang karena versinya terlalu lama, tetapi itu jauh lebih cepat terselesaikan
Masalah virtual environment di Python tetap rumit
Itu adalah alat OSS yang ditulis dengan Rust dan mengelola versi Python serta venv secara otomatis
Tinggal atur
pyproject.tomllalu jalankanpyflow main.py, maka ia akan memasang dan mengunci dependensi seperti Cargo, sekaligus otomatis menyesuaikan versi Python yang cocok untuk proyekSaat itu Poetry dan Pipenv populer, tetapi keduanya masih kurang dalam hal venv dan manajemen versi
Biasanya saya memakai
uv add, dan hanya memakaiuv pipsaat diperlukanTetapi
uv piptetap mewarisi keterbatasan pip — resolusi dependensi bisa berubah tergantung urutan instalasiMemasang
dep-adulu laludep-b, membalik urutannya, atau memasang keduanya sekaligus bisa memberi hasil berbedaIni lebih merupakan masalah pip, tetapi kekacauan manajemen paket Python masih tetap ada
uv akan mengunduhnya sendiri
Go secara eksplisit menolak dukungan shebang
Sebagai gantinya, yang direkomendasikan adalah memakai
gorunBisa dijalankan dengan trik POSIX seperti
/// 2>/dev/null ; gorun "$0" "$@" ; exit $?Nim, Zig, dan D bisa dipakai dengan cara serupa lewat opsi
-run, sedangkan Swift, OCaml, dan Haskell dapat mengeksekusi file secara langsungTautan diskusi terkait
go runyaegi GitHub
Tulisan yang bilang “saya tidak mau tahu perbedaan pip, poetry, uv, saya cuma ingin menjalankan kodenya” pada akhirnya adalah soal tingkat kemahiran teknis
uv rundan PEP 723 sebenarnya sudah menyelesaikan semua masalahuv runmunculSaya sudah memakai Python lebih dari 20 tahun, tetapi codebase dengan paket eksternal atau venv selalu terasa menakutkan
Berkat
uv run, semua proyek kantor sudah saya pindahkan, tetapi proyek pribadi sudah telanjur berpindah ke GoDalam jangka panjang saya lebih suka bahasa bertipe statis
Pengguna cuma ingin programnya berjalan
uv rundan PEP 723 memang menyelesaikan masalahnya, tetapi tetap ada hambatan masuk karena pengguna harus tahu soal uvSelama uv bukan alat default resmi, banyak pengguna akan meninggalkan Python
Menurut saya ini ide yang benar-benar brilian
Namun scripting membutuhkan ergonomi yang berbeda dari perangkat lunak untuk distribusi
bash itu improvisasional, Go cocok untuk diproduktisasi, Python ada di tengah-tengah, Ruby lebih dekat ke bash, dan Rust lebih dekat ke Go
Skrip berguna saat kita perlu cepat menggabungkan perintah OS untuk menangani pekerjaan sekali pakai
Go kurang punya sifat improvisasional itu
Saya mencoba menjalankan aplikasi gtk sederhana di Debian dengan uv, dependensinya sudah benar tetapi tetap tidak jalan dan akhirnya Core Dump
Hal seperti ini terulang setiap kali saya mencoba Python lagi
Go memang verbose, tetapi setelah dikompilasi, ia tinggal berjalan saja
Intinya adalah apakah semuanya bisa selesai dalam satu file
Skrip 500 baris masih mungkin dibuat di Go, tetapi bahasanya sendiri memang mengasumsikan banyak file dan modul
Tidak didukungnya bang-line juga karena alasan itu
Toh kalau
go runpada akhirnya membuat biner sementara, menurut saya lebih baik sekalian build lalu taruh di/usr/local/binbash juga hanyalah lapisan abstraksi di atas OS, sama seperti Python, hanya saja terasa begitu karena ia shell bawaan
Terutama ke arah membuat kode yang ditulis LLM lebih mudah dibaca manusia
Saya setuju bahwa pengguna yang baru mengenal Python tidak perlu tahu perbedaan antara pip, poetry, dan uv
Tetapi kalau seseorang menulis artikel tentang topik ini, setidaknya dia harus tahu bahwa uv menyelesaikan masalah tersebut
Kritik yang lahir dari ketidaktahuan tidak meyakinkan
Saya juga penasaran karena belum sepenuhnya memahami konsep uv
Saya suka menulis skrip dengan Python
Saya bisa bekerja cepat, dan untuk tugas sederhana enak karena tidak perlu terlalu memikirkan tipe atau memori
Tetapi saya tidak ingin memakainya untuk aplikasi besar
Di kebanyakan sistem sudah ada Python bawaan, jadi itu cukup untuk skrip sederhana
Kalau mengingat kita tetap harus memasang Go, menurut saya lebih masuk akal memakai Python dengan uv
Seperti kata penulis bahwa ia “memulainya sedikit dengan trolling”, pada akhirnya ini memang soal preferensi terhadap Go
Cukup
node bla.jslalu selesaiKita harus tahu fungsi mengembalikan apa, dan kalau sudah paham bahasanya, tipe dasar biasanya cukup diingat saja
Ini juga berlaku pada bahasa bertipe statis
Kalau mempertimbangkan orang lain, sebaiknya jangan menulis kode distribusi dengan Python
Saya tadinya mengira ini akan jadi kritik terhadap Python, tetapi ternyata justru tip yang berguna
Kalau bahasanya memakai
//sebagai komentar, trik ini bisa diterapkan jugaC/C++, Java, JavaScript, Rust, Swift, Kotlin, ObjC, D, F#, GLSL, dan lainnya memungkinkan
Terutama menarik untuk membuat demo grafis satu file dengan GLSL
Contoh Shadertoy
Di C, ini juga bisa dilakukan dengan komentar blok seperti
/*/../usr/bin/env gcc "$0" "$@"; ./a.out; rm -vf a.out; exit; */Konsepnya seperti uv untuk Swift
Swift juga secara resmi mendukung shebang
#!juga bisa langsung dipakaiDulu pada masa TCC, orang memakai cara ini untuk “C scripting”
Dalam proyek besar, skrip build akan membaca manifest lalu build dan menjalankannya
Tetapi karena kontrol lingkungannya sulit, pendekatan ini kurang cocok untuk pekerjaan nyata
Rust mendukung shebang secara langsung
Kalau ingin bahasa yang lebih ergonomis, .NET 10 juga punya fitur “run file directly”
Ia mendukung shebang, dan otomatis memasang paket dari dalam skrip
Dengan direktif
#:sdk, aplikasi web pun bisa langsung dijalankanHanya saja kompilasi AOT masih terasa kasar
Awalnya saya kira ini akan jadi kritik terhadap Python, tetapi malah membuat saya memikirkan arah ekosistem bahasa
Menurut saya, fakta bahwa ML terikat pada Python adalah kesalahan besar
Karena lambat, sistem tipenya tidak nyaman, dan distribusinya sulit
Sekarang sudah saatnya mempertimbangkan alternatif seperti TypeScript, Go, dan Rust
Tetapi alasan ML memilih Python adalah karena FFI berbasis C
NodeJS, Rust, dan Go lemah dalam hal FFI
Di sinilah Python punya keunggulan
Yang ideal adalah bahasa yang sesederhana Python tetapi punya sistem tipe dan skema distribusi yang lebih baik
Saya tidak ingin mengganti Python dengan bahasa yang lahir dari ekosistem JS
Lisp atau Lua (Torch) sebenarnya lebih cocok, tetapi Python dipilih karena kesederhanaannya
Saya sendiri sedang mengembangkan framework ML berbasis Lisp, tetapi sepertinya akan sulit diadopsi
Karena masalah kompatibilitas versi, tidak adanya semver, dan ekosistem yang tidak stabil, rasanya Python justru tertinggal dari JS
JS/Node sudah matang dalam 10 tahun terakhir, tetapi Python masih seperti tertahan di 2012
Sangat disayangkan bahwa ML distandardkan ke Python
Saat membuat alat CLI, Go jauh lebih cepat daripada Python
Saya sempat kembali ke Python karena perbedaan LOC, tetapi setiap kali menjalankannya saya malah rindu Go
Mungkin OCaml yang ideal, tetapi tooling yang kuno terasa membebani
Masalah dengan skrip Go adalah baris pertama tidak boleh memiliki spasi awal
Karena
goplsmemaksa pemformatan otomatisKonsistensi format juga harus dijaga di CI, jadi ini penting dalam praktik
Tetapi masalah yang lebih besar adalah tidak bisa memakai go.mod
Artinya, kita tidak bisa menentukan versi dependensi sehingga jaminan kompatibilitas menjadi lebih lemah