- Go dosyalarını çalıştırılabilir dosya gibi doğrudan çalıştırmayı sağlayan bir hile tanıtılıyor
- İlk satıra
//usr/local/go/bin/go run "$0" "$@"; exit koyup çalıştırma izni verirseniz ./script.go ile çalıştırabilirsiniz
- Bu yöntem shebang değil; POSIX'te ENOEXEC oluştuğunda kabuğun /bin/sh'e fallback yapması davranışını kullanıyor
- Kabuk ilk satırı komut olarak çalıştırıyor, Go derleyicisi ise bunu
// yorumu olarak görüp yok sayıyor
"$0" ile kendi dosya yolunu geçirerek go run'ın betiği derleyip çalıştırması, $@ ile de argümanların aktarılması sağlanıyor
- Go'nun güçlü standart kütüphanesi ve geriye dönük uyumluluk garantisi, onu betik yazımı için uygun kılıyor; Go 1.x sürümü kullanıldığı sürece betikler onlarca yıl çalışabilir
- Python'daki sanal ortam, pip/poetry/uv gibi bağımlılık yönetimi karmaşıklıklarından kaçınılabilir
Sahte shebang nasıl çalışıyor
- shebang (
#!), yorumlayıcıyı execve sistem çağrısı üzerinden belirler; ancak bu yazıda anlatılan teknik bir shebang değildir
- Go kaynak dosyasının ilk satırına
//usr/local/go/bin/go run "$0" "$@"; exit yazıp, altına package main ve normal Go kodu koyma yaklaşımı kullanılıyor
chmod +x script.go ile çalıştırma izni verirseniz ./script.go gibi çalıştırabilirsiniz
strace ile bakıldığında, kabuk ./script.go için execve denediğinde çekirdeğin ENOEXEC (Exec format error) döndürdüğü görülüyor
- ENOEXEC alan kabuk, fallback olarak
/bin/sh kullanıp ilgili dosyayı kabuk betiği olarak yorumluyor
- Kabukta
// yorum değil, kök yol (/) olarak yorumlandığından //usr/local/go/bin/go geçerli bir yol olarak çalışıyor
- Böylece ilk satır
//usr/local/go/bin/go run "$0" "$@"; exit, kabuk tarafından komut olarak yürütülüyor
"$0", çalıştırılan dosyanın yolunu ilettiği için komutta script.go yoluna dönüşüyor ve go run kendi dosyasını bulup derleyerek çalıştırıyor
"$@", 1. argümandan itibaren konumsal argümanları genişlettiğinden ./script.go -f flag0 here are some args gibi çağrılar mümkün oluyor
; exit olmazsa sh, Go dosyasını satır satır yorumlamayı sürdürür ve package gibi belirteçlerde hata verir
Go neden betik yazımı için uygun
- Go'nun geriye dönük uyumluluk garantisi temel avantajlardan biri; Go 1.x kullanıldığı sürece yazdığınız betikler uzun süre çalışır
- İyi gelişmiş standart kütüphane ve yerleşik araçlar (formatter, linter vb.) ek ayar gerektirmeden sunulduğundan, betik paylaşımı ve taşınabilirlik en üst düzeye çıkar
- Python'daki gibi sanal ortam ya da farklı paket yöneticilerini (pip, poetry, uv) öğrenmeden kod çalıştırılabilir
- Go ekosisteminin yerleşik araçları ve IDE entegrasyonu sayesinde
.pyproject ya da package.json olmadan da formatter ve linter'lar varsayılan olarak kullanılabilir
- Sadece güncel bir Go kurulumu varsa, herhangi bir işletim sisteminde onlarca yıl çalıştırılabilir
Diğer derlenen dillerle karşılaştırma
- Rust'ta derleme yavaştır, standart kütüphane daha zayıftır, bu yüzden bağımlılık kullanımı neredeyse zorunludur; ayrıca mükemmellik beklentisi geliştirme hızını düşürür
- Java ve JVM dilleri tarafında zaten JVM bayt kodu tabanlı betik dilleri vardır; ayrıca hafif Kotlin betik yazımı da bir alternatif olabilir
- Go, derlenen diller arasında betik kullanımı için en uygun özellikleri taşıyor
gopls biçimlendirme sorunu ve çözümü
gopls, yorumdan sonra boşluk ister (//example → // example), bu yüzden sahte shebang satırı bozulur
- Boşluk eklendiğinde
// usr/local/go/bin/go olur ve kabuk bunu yol olarak algılamaz
- Çözüm: HN başlığındaki öneri doğrultusunda
// yerine /**/ blok yorumu kullanmak
/*usr/local/go/bin/go run "$0" "$@"; exit; */ biçiminde yazılabilir
exit sonrasındaki noktalı virgül (;) zorunludur
1 yorum
Hacker News yorumları
Yazarın söylediği “pip vs poetry vs uv umurumda değil” kısmı aslında uv tarafından bu kullanım senaryosu için doğrudan destekleniyor
PyPI bağımlılıkları dahil, yalnızca Python sürümü ve uv kurulu olsa yeterli
uv resmi dokümantasyon bağlantısı
#!/usr/bin/env -S uv run --python 3.14 --scriptBunu yapınca Python’ın kendisi kurulu olmasa bile uv belirtilen sürümü indirip çalıştırıyor
Clojure ile ilk kez karşılaşan çoğu kişi Leiningen kullanması gerektiği tavsiyesini duyar ama Python’da arama yapınca venv, poetry, hatch, uv gibi pek çok seçenek çıkıyor
uv giderek baskın araç hâline geliyor ama henüz evrensel değil
Geçmişte Go’yu apt ile kurup sürüm çok eski olduğu için yeniden kurmak zorunda kalmıştım, ama o sorun çok daha hızlı çözülmüştü
Python’un sanal ortam meselesi hâlâ karmaşık
Rust ile yazılmış bir OSS araç; Python sürümünü ve venv’i otomatik yönetiyor
Sadece
pyproject.tomlayarlayıppyflow main.pyçalıştırıyorsunuz; Cargo gibi bağımlılıkları kurup kilitliyor, projeye uygun Python sürümünü de otomatik ayarlıyorO dönemde Poetry ve Pipenv popülerdi ama venv ve sürüm yönetimi konusunda yetersizdi
Genelde
uv addkullanıyorum,uv pipise yalnızca gerektiğindeAma
uv pip, pip’in sınırlamalarını aynen taşıyor — bağımlılık çözümleme kurulum sırasına göre değişiyoruv pip install dep-aardındandep-bkurmakla, sıralamayı değiştirmek ya da ikisini tek seferde kurmak aynı şey değilBu daha çok pip’in sorunu ama Python paket yönetimindeki karmaşa hâlâ sürüyor
uv onu kendisi indiriyor
Go, shebang desteğini açıkça reddetti
Bunun yerine
gorunkullanılması öneriliyor/// 2>/dev/null ; gorun "$0" "$@" ; exit $?gibi POSIX hileleriyle çalıştırmak mümkünNim, Zig, D benzer şekilde
-runseçeneğiyle kullanılabiliyor; Swift, OCaml, Haskell ise dosyayı doğrudan çalıştırabiliyorİlgili tartışma bağlantısı
go runyerine yaegi yorumlayıcısı daha iyi olabiliryaegi GitHub
“pip, poetry, uv arasındaki farkı bilmek istemiyorum, sadece kodu çalıştırmak istiyorum” diyen yazı sonuçta bir teknik yetkinlik meselesi
uv runve PEP 723 zaten tüm sorunları çözmüş durumdauv rungelene kadar çok fazla zaman geçti20 yıldan uzun süredir Python kullanıyorum ama dış paketleri ya da venv’i olan bir kod tabanı her zaman gözümü korkuttu
uv runsayesinde şirketteki tüm projeleri taşıdım ama kişisel projelerde çoktan Go’ya geçmiştimUzun vadede statik tipli dilleri tercih ediyorum
Kullanıcı sadece programın çalışmasını istiyor
uv runve PEP 723 sorunu çözmüş olsa da, uv’yi bilmeniz gerekmesi hâlâ bir giriş engeliuv resmi varsayılan araç olmadığı sürece çok kişi Python’dan uzaklaşacak
Bunun gerçekten dahiyane bir fikir olduğunu düşünüyorum
Ama script yazımı, dağıtılan yazılımlardan farklı bir ergonomi hissi gerektiriyor
bash doğaçlamaya uygun, Go ürünleştirmeye uygun; Python ikisinin arasında, Ruby bash’e daha yakın, Rust ise Go tarafında
Script’ler, OS komutlarını hızlıca birleştirip tek seferlik işleri çözmek için faydalı
Go’da bu tür doğaçlama hissi eksik
Debian’da basit bir gtk uygulamasını uv ile çalıştırmaya çalıştım; tüm bağımlılıklar doğruydu ama yine de çalışmadı ve sonuç Core Dump oldu
Python’a her yeni girişimde bu tekrar yaşanıyor
Go daha ayrıntılı ama bir kez derlenince gerçekten çalışıyor
Asıl mesele bunun tek dosyada bitip bitmediği
Go ile de 500 satırlık script yazılabilir ama dilin kendisi birden fazla dosya ve modül varsayıyor
bang-line desteğinin olmaması da bununla ilgili
Zaten
go rungeçici bir binary üretiyorsa, bence doğrudan build edip/usr/local/biniçine koymak daha iyibash de Python kadar OS üzerinde bir soyutlama katmanı; sadece varsayılan shell olduğu için öyle hissediliyor
Özellikle de LLM’in yazdığı kodun insanlar için kolay okunur olması açısından
Python’a yeni başlayan bir kullanıcının pip, poetry, uv farklarını bilmek zorunda olmaması gerektiğine katılıyorum
Ama bu konuda yazı yazan bir blog yazarının en azından uv’nin sorunu çözdüğünü bilmesi gerekir
Bilgisiz eleştiri ikna edici değil
Ben de uv kavramını tam anlamadığım için merak ediyorum
Python ile script yazmayı seviyorum
Hızlı çalışmayı sağlıyor ve tip ya da bellek kaygısı olmadan basit işleri çözmek için iyi
Ama büyük ölçekli uygulamalarda kullanmak istemem
Çoğu sistemde varsayılan Python bulunduğu için basit script’ler için yeterli oluyor
Go kurma gerekliliğini düşününce, bence uv ile Python kullanmak daha mantıklı
Yazarın da dediği gibi “biraz trollük olsun diye başladım”, yani sonuçta mesele Go tercihi
node bla.jsdeyip geçiyorsunuzBir fonksiyonun ne döndürdüğünü bilmeniz gerekir ve dili iyi biliyorsanız temel tipleri hafızadan halledersiniz
Bu, statik tipli diller için de geçerli
Başkalarını düşünüyorsanız dağıtılacak kodu Python ile yazmamalısınız
Python eleştirisi bekliyordum ama tersine faydalı bir ipucu çıktı
//yorum kullanan dillerde bu hile uyarlanabilirC/C++, Java, JavaScript, Rust, Swift, Kotlin, ObjC, D, F#, GLSL vb. için mümkün
Özellikle GLSL ile tek dosyalık grafik demoları üretme fikri ilginç
Shadertoy örneği
C’de blok yorumla
/*/../usr/bin/env gcc "$0" "$@"; ./a.out; rm -vf a.out; exit; */gibi yöntemler de mümkünSwift için uv benzeri bir fikir
Swift shebang’i de resmi olarak destekliyor
#!doğrudan da kullanılabiliyorEski TCC zamanlarında bunu “C scripting” için kullanmıştım
Büyük projelerde build script’i manifest’i okuyup derleme sonrası çalıştırıyordu
Ama ortamı kontrol etmek zor olduğu için gerçek işte pek uygun değil
shebang’i doğrudan destekliyor
Daha ergonomik bir dil istiyorsanız .NET 10’un “run file directly” özelliği de var
shebang destekliyor ve script içinde paketleri otomatik kuruyor
#:sdkyönergesiyle web uygulamaları bile doğrudan çalıştırılabiliyorYalnız AOT derleme tarafı hâlâ biraz ham
Başta Python eleştirisi sanmıştım ama aslında dil ekosisteminin yönünü düşündürdü
ML’in Python’a bağlanmış olması bence büyük bir hataydı
Çünkü yavaş, tip sistemi rahatsız edici ve dağıtımı zor
Artık TypeScript, Go, Rust gibi alternatifler düşünülmeli
Ama ML’in Python’u seçmesinin nedeni C tabanlı FFI idi
NodeJS, Rust ve Go FFI tarafında zayıf
Python burada güçlü
İdeal olan, Python kadar basit ama daha iyi bir tip sistemi ve dağıtım yapısına sahip bir dil olurdu
JS ekosisteminden çıkmış bir dille Python’u değiştirmek istemem
Lisp ya da Lua (Torch) daha uygun olabilirdi ama sadelik yüzünden Python seçildi
Ben de Lisp tabanlı bir ML framework’ü geliştiriyorum ama benimsenmesi zor görünüyor
Sürüm uyumluluğu sorunları, semver eksikliği, istikrarsız ekosistem gibi nedenlerle JS’den bile geri kalmış gibi hissettiriyor
JS/Node son 10 yılda olgunlaştı ama Python hâlâ 2012’de kalmış gibi
ML’in Python’da standartlaşmış olması gerçekten üzücü
CLI araçları yaparken Go, Python’dan çok daha hızlı
LOC farkı yüzünden Python’a geri dönmüş olsam da, her çalıştırdığımda Go’yu özlüyorum
Muhtemelen OCaml ideal olurdu ama eski araç zinciri göz korkutuyor
Go script’lerinin sorunu, ilk satırda boşluk olamaması
Çünkü
goplsotomatik biçimlendirmeyi dayatıyorCI’da da biçim tutarlılığını korumak gerektiği için bu pratikte önemli
Ama daha büyük sorun go.mod kullanılamaması
Yani bağımlılık sürümlerini sabitleyemiyorsunuz; bu da uyumluluk garantisini zayıflatıyor