23 पॉइंट द्वारा GN⁺ 2025-12-31 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Go फ़ाइलों को executable की तरह सीधे चलाने की एक ट्रिक का परिचय
  • पहली पंक्ति में //usr/local/go/bin/go run "$0" "$@"; exit रखें और execute permission दें, तो ./script.go से चलाया जा सकता है
  • यह तरीका shebang नहीं है, बल्कि POSIX में ENOEXEC होने पर shell के /bin/sh पर fallback करने वाले व्यवहार का उपयोग करता है
  • shell पहली पंक्ति को command की तरह चलाता है, और Go compiler उसे // comment मानकर नज़रअंदाज़ कर देता है
  • "$0" से अपनी ही path पास की जाती है, इसलिए go run script को build और execute करता है, और $@ से arguments पास होते हैं
  • Go की मज़बूत standard library और backward compatibility की गारंटी इसे scripting के लिए उपयुक्त बनाती है, और Go 1.x version इस्तेमाल करने पर script दशकों तक चल सकती है
  • Python के virtual environment, pip/poetry/uv जैसी dependency management की जटिलता से बचा जा सकता है

नकली shebang कैसे काम करता है

  • shebang(#!) execve system call के ज़रिए interpreter तय करने का तरीका है, लेकिन यहाँ बताई गई तकनीक shebang नहीं है
  • Go source file की पहली पंक्ति में //usr/local/go/bin/go run "$0" "$@"; exit रखकर, उसके नीचे package main और सामान्य Go code लिखा जाता है
    • chmod +x script.go से execute permission देने पर इसे ./script.go की तरह चलाया जा सकता है
  • strace से देखने पर पता चलता है कि shell जब ./script.go को execve से चलाने की कोशिश करता है, तो kernel ENOEXEC(Exec format error) लौटाता है
    • ENOEXEC मिलने पर shell fallback के तौर पर /bin/sh का उपयोग करके उसी फ़ाइल को shell script की तरह interpret करता है
    • shell में // comment नहीं है, बल्कि root path(/) की तरह interpret होता है, इसलिए //usr/local/go/bin/go एक वैध path की तरह execute हो जाता है
  • इसलिए पहली पंक्ति //usr/local/go/bin/go run "$0" "$@"; exit shell में command की तरह execute होती है
    • "$0" execute की गई फ़ाइल का path देता है, इसलिए command में "$0" script.go path बन जाता है और go run उसी फ़ाइल को ढूँढकर build और execute करता है
    • "$@" positional arguments expansion है, जिससे ./script.go -f flag0 here are some args जैसी invocation संभव होती है
    • ; exit न हो तो sh Go फ़ाइल को आगे भी लाइन-दर-लाइन interpret करता रहेगा और package जैसे token पर error देगा

Go scripting के लिए उपयुक्त क्यों है

  • Go की backward compatibility की गारंटी इसकी मुख्य विशेषताओं में से है, इसलिए Go 1.x इस्तेमाल करने पर लिखी गई script लंबे समय तक चलती रहती है
  • अच्छी तरह विकसित standard library और built-in tools (formatter, linter आदि) बिना अलग setup के मिलते हैं, जिससे script sharing और portability अधिकतम हो जाती है
    • Python की तरह virtual environment या अलग-अलग package managers (pip, poetry, uv) सीखे बिना code चलाया जा सकता है
    • Go ecosystem के built-in tools और IDE integration की वजह से .pyproject या package.json के बिना भी formatter और linter डिफ़ॉल्ट रूप से इस्तेमाल किए जा सकते हैं
  • अगर सिर्फ़ नया Go installed हो, तो किसी भी OS पर दशकों तक चलाया जा सकता है

दूसरी compiled languages से तुलना

  • Rust में compile speed धीमी है, standard library अपेक्षाकृत कमज़ोर है, dependency का उपयोग लगभग अनिवार्य हो जाता है, और perfectness पर ज़ोर होने से development speed धीमी पड़ती है
  • Java और JVM भाषाओं में पहले से JVM bytecode आधारित scripting languages मौजूद हैं, और हल्की Kotlin scripting भी एक विकल्प हो सकती है
  • compiled languages में Go के पास scripting use case के लिए सबसे उपयुक्त गुण हैं

gopls formatting समस्या और समाधान

  • gopls comment के बाद space मांगता है (//example// example), इसलिए नकली shebang लाइन टूट जाती है
  • space आ जाने पर // usr/local/go/bin/go बन जाता है, जिसे shell path की तरह नहीं पहचानता
  • समाधान: HN thread के सुझाव के अनुसार // की जगह /**/ block comment का उपयोग करें
    • इसे /*usr/local/go/bin/go run "$0" "$@"; exit; */ के रूप में लिखा जा सकता है
    • exit के बाद semicolon(;) अनिवार्य है

1 टिप्पणियां

 
GN⁺ 2025-12-31
Hacker News की राय
  • लेखक ने जो “pip vs poetry vs uv की चिंता नहीं” वाली बात कही, दरअसल uv इस use case को सीधे support करता है
    PyPI dependencies सहित, बस Python version और uv installed होना चाहिए
    uv आधिकारिक दस्तावेज़ लिंक

    • इससे भी बेहतर तरीका है
      #!/usr/bin/env -S uv run --python 3.14 --script
      ऐसा करने पर Python खुद installed न हो तब भी uv तय किया गया version डाउनलोड करके चला देता है
    • मैं भी ऐसा ही सोचता था, लेकिन non-Python users के लिए यह अभी भी intuitive नहीं है
      Clojure को पहली बार सीखते समय ज़्यादातर लोग Leiningen इस्तेमाल करने की सलाह सुनते हैं, लेकिन Python में search करो तो venv, poetry, hatch, uv जैसी कई चीज़ें सामने आती हैं
      uv धीरे-धीरे main choice बन रहा है, लेकिन अभी universal नहीं है
      मैंने पहले Go को apt से install किया था और version बहुत पुराना निकला, तो दोबारा install करना पड़ा था, लेकिन वह समस्या इससे कहीं जल्दी हल हो गई
      Python के virtual environment की समस्या अब भी जटिल है
    • मैंने 2019 में PyFlow से यह समस्या हल की थी
      यह Rust में लिखा OSS tool है, जो Python version और venv को अपने-आप manage करता है
      बस pyproject.toml सेट करो और pyflow main.py चलाओ, तो यह Cargo की तरह dependency install और lock करता है, और project के हिसाब से Python version भी अपने-आप match कर देता है
      उस समय Poetry और Pipenv लोकप्रिय थे, लेकिन venv और version management तक उनकी पहुंच कमज़ोर थी
    • मैं भी ज़्यादातर uv पर shift हो गया हूँ
      ज़्यादातर uv add इस्तेमाल करता हूँ, और ज़रूरत पड़ने पर ही uv pip
      लेकिन uv pip, pip की limitations उसी तरह रखता है — install order के हिसाब से dependency resolution बदल जाता है
      uv pip install dep-a के बाद dep-b install करना, order उलटना, या दोनों को एक साथ install करना — सबके result अलग हो सकते हैं
      यह ज़्यादा pip की समस्या है, लेकिन Python package management का confusion अभी भी बना हुआ है
    • सच कहें तो Python version भी specify करने की ज़रूरत नहीं है
      uv खुद डाउनलोड कर लेता है
  • Go ने shebang support को साफ़ तौर पर अस्वीकार किया है
    इसके बजाय gorun इस्तेमाल करने की सलाह दी जाती है
    /// 2>/dev/null ; gorun "$0" "$@" ; exit $? जैसी POSIX trick से इसे चलाया जा सकता है
    Nim, Zig, D में -run option से ऐसा ही किया जा सकता है, और Swift, OCaml, Haskell में file को सीधे execute किया जा सकता है
    संबंधित चर्चा लिंक

    • छोटे scripts के लिए go run की जगह yaegi interpreter बेहतर हो सकता है
      yaegi GitHub
  • “मैं pip, poetry, uv का फर्क नहीं जानना चाहता, बस code चलाना चाहता हूँ” जैसी बात आखिरकार technical proficiency की समस्या है
    uv run और PEP 723 पहले ही सारी समस्या हल कर चुके हैं

    • सही है, लेकिन uv run आने में बहुत देर हो गई
      मैं 20 साल से ज़्यादा समय से Python इस्तेमाल कर रहा हूँ, लेकिन external packages या venv वाले codebase हमेशा डराते रहे हैं
      uv run की वजह से मैंने company projects सब migrate कर दिए, लेकिन personal projects पहले ही Go पर चले गए
      लंबे समय में मैं statically typed languages को पसंद करता हूँ
    • अगर language पुरानी है, तो आखिरकार competing libraries सीखनी ही पड़ती हैं
    • यह UX problem है
      user बस चाहता है कि program चल जाए
      uv run और PEP 723 ने समस्या हल कर दी है, लेकिन uv के बारे में जानना पड़े, यह अब भी entry barrier है
      जब तक uv official default tool नहीं बनता, बहुत से users Python छोड़ते रहेंगे
  • मुझे यह सच में genius idea लगता है
    लेकिन scripting को deployment software से अलग तरह की ergonomics चाहिए
    bash ad-hoc है, Go productization के लिए अच्छा है, Python बीच में कहीं है, Ruby bash के करीब है, और Rust Go की तरफ़ है
    scripts OS commands को जल्दी-जल्दी जोड़कर one-off काम करने में काम आते हैं
    Go में वह improvisation कम है

    • मैं भी Python के “बीच में कहीं” होने वाली बात से सहमत हूँ
      Debian में एक simple gtk app को uv से चलाने की कोशिश की थी, dependencies सब सही थीं, फिर भी नहीं चला और आखिर में Core Dump
      Python को हर बार नए सिरे से आज़माने पर ऐसा कुछ हो ही जाता है
      Go verbose है, लेकिन एक बार compile हो जाए तो बस चलता है
    • मुझे भी कुछ ऐसा ही लगता है
      असली बात यह है कि क्या एक file में काम खत्म हो सकता है
      Go में 500-line script भी हो सकती है, लेकिन language खुद multiple files और modules को मानकर चलती है
      bang-line support न होना भी उसी वजह से है
      वैसे भी अगर go run अस्थायी binary बनाता ही है, तो मुझे लगता है सीधे build करके /usr/local/bin में डालना बेहतर है
    • bash के OS commands के ज़्यादा करीब होने की बात गलतफहमी है
      bash भी Python की तरह OS के ऊपर एक abstraction layer ही है, बस default shell होने की वजह से ऐसा महसूस होता है
    • अगर हम उस दौर में जा रहे हैं जहाँ LLM code खुद modify करेंगे, तो writing ergonomics से ज़्यादा readability महत्वपूर्ण हो सकती है
      खासकर उस दिशा में जहाँ LLM द्वारा लिखा code इंसानों के लिए पढ़ने में आसान बनाया जाए
  • मैं इस बात से सहमत हूँ कि Python पहली बार सीखने वाले user को pip, poetry, uv का फर्क जानने की ज़रूरत नहीं होनी चाहिए
    लेकिन अगर कोई ब्लॉगर इस विषय पर लिख रहा है, तो उसे कम-से-कम यह तो पता होना चाहिए कि uv इस समस्या का समाधान करता है
    अनजान आलोचना persuasive नहीं होती

    • एक सवाल है कि क्या uv, Go की तरह “write once, run anywhere” हल करता है
      मैं भी uv के concept को पूरी तरह नहीं समझ पाया हूँ, इसलिए जानना चाहता हूँ
  • मुझे Python में scripting करना पसंद है
    इसमें तेज़ी से काम हो जाता है, और type या memory की चिंता किए बिना simple काम करना आसान है
    लेकिन बड़े application के लिए मैं इसे नहीं चुनना चाहूँगा

    • मुझे भी Python scripting पसंद है, लेकिन दूसरों के scripts install करना पसंद नहीं
    • यह Linux-केंद्रित नज़रिया है
      ज़्यादातर systems में default Python होता है, इसलिए simple scripts के लिए वह काफ़ी है
      Go install करना पड़े, यह देखते हुए मुझे Python को uv के साथ इस्तेमाल करना ज़्यादा बेहतर लगता है
      जैसा लेखक ने भी कहा कि “मैंने थोड़ा trolling की तरह शुरू किया था”, आख़िर में यह Go preference का मामला है
    • मुझे JS भी scripting language के रूप में बुरा नहीं लगता
      node bla.js और काम खत्म
    • types की चिंता तो हमेशा करनी पड़ती है
      function क्या return करता है, यह जानना होता है, और language अच्छी तरह आ जाए तो basic types याद से संभाल लिए जाते हैं
      static type languages में भी यही बात लागू होती है
    • Python developers के लिए शानदार है, लेकिन deployment और integration के लिए दुःस्वप्न है
      अगर आपको दूसरे लोगों का भी ध्यान रखना है, तो Python में deployable code नहीं लिखना चाहिए
  • मैं Python की आलोचना की उम्मीद कर रहा था, लेकिन यह तो उल्टा useful tip निकला
    जिन languages में // comment के रूप में चलता है, उनमें इस trick को अपनाया जा सकता है
    C/C++, Java, JavaScript, Rust, Swift, Kotlin, ObjC, D, F#, GLSL आदि में यह संभव है
    खासकर GLSL से single-file graphics demo बनाना दिलचस्प लगता है
    Shadertoy उदाहरण
    C में block comment का उपयोग करके /*/../usr/bin/env gcc "$0" "$@"; ./a.out; rm -vf a.out; exit; */ जैसा तरीका भी इस्तेमाल किया जा सकता है

    • Swift में external dependencies वाले scripts चलाने के लिए swift-sh project है
      यह Swift के लिए uv जैसी अवधारणा है
      Swift आधिकारिक तौर पर shebang भी support करता है
    • C/C++ में #! सीधे भी लिखा जा सकता है
      पुराने TCC दौर में मैंने “C scripting” के लिए यह तरीका इस्तेमाल किया था
      बड़े projects में build script manifest पढ़कर build के बाद run करता था
      लेकिन environment control कठिन होने के कारण यह practical work में ठीक नहीं बैठता
    • Rust को ऐसी tricks की ज़रूरत नहीं
      वह shebang को सीधे support करता है
  • अगर आपको और ergonomic language चाहिए, तो .NET 10 की “run file directly” feature भी है
    यह shebang support करती है, और script के भीतर packages अपने-आप install कर देती है
    #:sdk directive से web app भी सीधे चलाया जा सकता है

    • मैंने भी आज पहली बार इस feature से C# script लिखी, और अनुभव काफ़ी अच्छा था
      बस AOT compilation अभी थोड़ी कच्ची है
  • शुरू में लगा था यह Python की आलोचना होगी, लेकिन इसने उल्टा language ecosystem की direction पर सोचने पर मजबूर कर दिया
    मेरे हिसाब से ML का Python से बंध जाना बड़ी गलती थी
    क्योंकि यह धीमा है, type system असुविधाजनक है, और deployment मुश्किल है
    अब TypeScript, Go, Rust जैसे alternatives पर विचार करना चाहिए

    • सहमत हूँ
      लेकिन ML ने Python चुना, उसकी वजह C-based FFI थी
      NodeJS, Rust, Go में FFI कमज़ोर है
      Python यहाँ मज़बूत है
      आदर्श रूप से हमें Python जितनी सरल, लेकिन बेहतर type system और deployment model वाली language चाहिए
    • TypeScript से बदलने वाली बात से मैं सहमत नहीं
      JS ecosystem से निकली language से Python को replace नहीं करना चाहता
    • ML का Python की ओर जाना market pressure की वजह से हुआ
      Lisp या Lua(Torch) ज़्यादा उपयुक्त थे, लेकिन simplicity की वजह से Python चुना गया
      मैं भी Lisp-आधारित ML framework बना रहा हूँ, लेकिन adoption मुश्किल लगती है
    • Python का dependency hell अब भी गंभीर है
      version compatibility issues, semver की कमी, unstable ecosystem जैसी वजहों से यह JS से पीछे लगता है
      JS/Node पिछले 10 साल में mature हुए हैं, लेकिन Python अभी भी 2012 में अटका लगता है
      ML का Python पर standardize होना सच में अफ़सोस की बात है
    • मुझे ऐसी language चाहिए जो सरल और expressive हो, साथ ही strongly typed + native compiled भी
      CLI tools बनाते समय Go, Python से कहीं तेज़ है
      LOC के फर्क की वजह से मैं Python पर लौट आता हूँ, लेकिन हर बार चलाते समय Go याद आता है
      शायद OCaml आदर्श हो, लेकिन पुराना tooling बोझिल लगता है
  • Go scripts की समस्या यह है कि पहली line में कोई whitespace नहीं होना चाहिए
    क्योंकि gopls auto-formatting enforce करता है
    CI में भी format consistency बनाए रखनी पड़ती है, इसलिए यह practical तौर पर महत्वपूर्ण है
    लेकिन बड़ी समस्या यह है कि go.mod इस्तेमाल नहीं किया जा सकता
    यानी dependency versions specify नहीं कर सकते, इसलिए compatibility guarantee कमज़ोर हो जाती है

    • फिर भी major versions import path से lock हो जाते हैं, इसलिए default रूप से कुछ compatibility बनी रहती है
    • यह language/runtime-level compatibility issue है, dependency issue नहीं