23 puan yazan GN⁺ 2025-12-31 | 1 yorum | WhatsApp'ta paylaş
  • 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

 
GN⁺ 2025-12-31
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ı

    • Bundan daha iyi bir yöntem de var
      #!/usr/bin/env -S uv run --python 3.14 --script
      Bunu yapınca Python’ın kendisi kurulu olmasa bile uv belirtilen sürümü indirip çalıştırıyor
    • Ben de öyle düşünmüştüm ama Python kullanıcısı olmayanlar için hâlâ sezgisel değil
      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
    • Ben bu sorunu 2019’da PyFlow ile çözmüştüm
      Rust ile yazılmış bir OSS araç; Python sürümünü ve venv’i otomatik yönetiyor
      Sadece pyproject.toml ayarlayıp pyflow main.py çalıştırıyorsunuz; Cargo gibi bağımlılıkları kurup kilitliyor, projeye uygun Python sürümünü de otomatik ayarlıyor
      O dönemde Poetry ve Pipenv popülerdi ama venv ve sürüm yönetimi konusunda yetersizdi
    • Ben de çoğunlukla uv’ye geçtim
      Genelde uv add kullanıyorum, uv pip ise yalnızca gerektiğinde
      Ama 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şiyor
      uv pip install dep-a ardından dep-b kurmakla, sıralamayı değiştirmek ya da ikisini tek seferde kurmak aynı şey değil
      Bu daha çok pip’in sorunu ama Python paket yönetimindeki karmaşa hâlâ sürüyor
    • Aslında Python sürümünü bile belirtmeye gerek yok
      uv onu kendisi indiriyor
  • Go, shebang desteğini açıkça reddetti
    Bunun yerine gorun kullanılması öneriliyor
    /// 2>/dev/null ; gorun "$0" "$@" ; exit $? gibi POSIX hileleriyle çalıştırmak mümkün
    Nim, Zig, D benzer şekilde -run seçeneğiyle kullanılabiliyor; Swift, OCaml, Haskell ise dosyayı doğrudan çalıştırabiliyor
    İlgili tartışma bağlantısı

    • Küçük script’lerde go run yerine yaegi yorumlayıcısı daha iyi olabilir
      yaegi GitHub
  • “pip, poetry, uv arasındaki farkı bilmek istemiyorum, sadece kodu çalıştırmak istiyorum” diyen yazı sonuçta bir teknik yetkinlik meselesi
    uv run ve PEP 723 zaten tüm sorunları çözmüş durumda

    • Doğru, ama uv run gelene kadar çok fazla zaman geçti
      20 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 run sayesinde şirketteki tüm projeleri taşıdım ama kişisel projelerde çoktan Go’ya geçmiştim
      Uzun vadede statik tipli dilleri tercih ediyorum
    • Eski bir dilse, sonunda rakip kütüphaneleri öğrenmek zorunda kalırsınız
    • Bu bir UX sorunu
      Kullanıcı sadece programın çalışmasını istiyor
      uv run ve PEP 723 sorunu çözmüş olsa da, uv’yi bilmeniz gerekmesi hâlâ bir giriş engeli
      uv 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

    • Ben de Python’un “arada bir yerde” olduğu fikrine katılıyorum
      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
    • Ben de benzer hissediyorum
      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 run geçici bir binary üretiyorsa, bence doğrudan build edip /usr/local/bin içine koymak daha iyi
    • bash’in OS komutlarına daha yakın olduğu fikri bir yanlış anlama
      bash de Python kadar OS üzerinde bir soyutlama katmanı; sadece varsayılan shell olduğu için öyle hissediliyor
    • LLM’lerin kodu sizin yerinize düzenlediği bir çağda, yazma ergonomisinden çok okunabilirlik daha önemli hâle gelebilir
      Ö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

    • uv’nin Go gibi “write once, run anywhere” sorununu çözüp çözmediğini soranlar var
      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

    • Ben de Python script yazımını seviyorum ama başkasının script’ini kurmaktan hoşlanmıyorum
    • Bu Linux merkezli bir yaklaşım
      Ç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
    • JS’nin de script dili olarak fena olmadığını düşünüyorum
      node bla.js deyip geçiyorsunuz
    • Tipleri her zaman düşünmek gerekir
      Bir 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
    • Python geliştirici için harika ama dağıtım ve entegrasyon için kâbus
      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 uyarlanabilir
    C/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ün

    • Swift tarafında dış bağımlılıklı script çalıştırabilen bir swift-sh projesi var
      Swift için uv benzeri bir fikir
      Swift shebang’i de resmi olarak destekliyor
    • C/C++ tarafında #! doğrudan da kullanılabiliyor
      Eski 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
    • Rust’un böyle hilelere ihtiyacı yok
      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
    #:sdk yönergesiyle web uygulamaları bile doğrudan çalıştırılabiliyor

    • Ben de bugün bu özellikle ilk kez C# script yazdım ve deneyim gayet iyiydi
      Yalnı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

    • Katılıyorum
      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
    • Yerine TypeScript geçsin fikrine katılmıyorum
      JS ekosisteminden çıkmış bir dille Python’u değiştirmek istemem
    • ML’in Python’a gitmesi pazar baskısı yüzündendi
      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
    • Python’un bağımlılık cehennemi hâlâ çok ciddi
      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ü
    • Ben sade ve ifade gücü yüksek, aynı zamanda güçlü tipli + native derlenen bir dil istiyorum
      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ü gopls otomatik biçimlendirmeyi dayatıyor
    CI’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

    • Yine de major sürümler import yolu üzerinden kilitlendiği için temel düzeyde uyumluluk var
    • Bu dil/runtime düzeyinde bir uyumluluk sorunu; bağımlılık sorunu değil