Go Away Python

(lorentz.app)

166 points | by baalimago 6 hours ago

34 comments

  • bushbaba 2 minutes ago
    This is great. Means my scripts in a golang repo can also be written in Golang vs bash/python. It can even import libs from my project.

    Awesome!

  • hamishwhc 4 hours ago
    The author’s point about “not caring about pip vs poetry vs uv” is missing that uv directly supports this use case, including PyPI dependencies, and all you need is uv and your preferred Python version installed: https://docs.astral.sh/uv/guides/scripts/#using-a-shebang-to...
    • meander_water 4 hours ago
      Actually you can go one better:

        #!/usr/bin/env -S uv run --python 3.14 --script
      
      Then you don't even need python installed. uv will install the version of python you specified and run the command.
      • rikafurude21 3 hours ago
        alternatively, uv lets you do this:

          #!/usr/bin/env -S uv run --script
          #
          # /// script
          # requires-python = ">=3.12"
          # dependencies = ["foo"]
          # ///
        • semi-extrinsic 51 minutes ago
          The /// script block is actually specified in PEP 723 and supported by several other tools apart from uv.
        • zahlman 36 minutes ago
          This isn't really "alternatively"; it's pointing out that in addition to the shebang you can add a PEP 723 dependency specification that `uv run` (like pipx, and some other tools) can take into account.
      • dietr1ch 1 hour ago
        Yeah, but you need `uv`. If we are reaching out for tools that might not be around, then you can also depend on nix-shell,

            #! /usr/bin/env nix-shell
            #! nix-shell -i python3 --packages python3
        • mystifyingpoi 40 minutes ago
          Yeah, but you need Nix. If we are reaching out for tools that might not be around, then you can also depend on `curl | sudo bash` to install Nix when not present.

          (this is a joke btw)

          • jonhohle 15 minutes ago
            Yeah, but you need curl, sudo, and bash…
      • jonhohle 16 minutes ago
        That shebang will work on GNU link based systems, but might not work elsewhere. I know that’s the most popular target, but not working on macOS, BSDs, or even busybox.
    • benrutter 4 hours ago
      I thought that too, but I think the tricky bit is if you're a non-python user, this isn't yet obvious.

      If you've never used Clojure and start a Clojure project, you will almost definitely find advice telling you to use Leiningen.

      For Python, if you search online you might find someone saying to use uv, but also potentially venv, poetry or hatch. I definitely think uv is taking over, but its not yet ubiquitous.

      Ironically, I actually had a similar thing installing Go the other day. I'd never used Go before, and installed it using apt only to find that version was too old and I'd done it wrong.

      Although in that case, it was a much quicker resolution than I think anyone fighting with virtual environments would have.

      • idoubtit 3 hours ago
        That's my experience. I'm not a Python developer, and installing Python programs has been a mess for decades, so I'd rather stay away from the language than try another new tool.

        Over the years, I've used setup.py, pip, pipenv (which kept crashing though it was an official recommendation), manual venv+pip (or virtualenv? I vaguely remember there were 2 similar tools and none was part of a minimal Python install). Does uv work in all of these cases? The uv doc pointed out by the GP is vague about legacy projects, though I've just skimmed through the long page.

        IIRC, Python tools didn't share their data across projects, so they could build the same heavy dependencies multiple times. I've also seen projects with incomplete dependencies (installed through Conda, IIRC) which were a major pain to get working. For many years, the only simple and sane way to run some Python code was in a Docker image, which has its own drawbacks.

        • lexicality 2 hours ago
          > Does uv work in all of these cases?

          Yes. The goal of uv is to defuck the python ecosystem and they're doing a very good job at it so far.

          • prox 1 hour ago
            What are the big offenders right now? What does uv unfuck?

            I only work a little bit with python.

          • aeurielesn 1 hour ago
            That's giving way too much credit to uv.
            • karel-3d 1 hour ago
              uv is really that good.
        • simonw 2 hours ago
          > IIRC, Python tools didn't share their data across projects, so they could build the same heavy dependencies multiple times.

          One of the neatest features of uv is that it uses clever symlinking tricks so if you have a dozen different Python environments all with the same dependency there's only one copy of that dependency on disk.

          • zahlman 22 minutes ago
            Hard links, in fact. It's not hard to do, just (the Rust equivalent of) `os.link` in place of `os.copy` pretty much. The actually clever part is that the package cache actually contains files that can be used this way, instead of just having wheels and unpacking them from scratch each time.

            For pip to do this, first it would have to organize its cache in a sensible manner, such that it could work as an actual download cache. Currently it is an HTTP cache (except for locally-built wheels), where it uses a vendored third-party library to simulate the connection to files.pythonhosted.org (in the common PyPI case). But it still needs to connect to pypi.org to figure out the URI that the third-party library will simulate accessing.

        • runjake 1 hour ago
          I would not be putting up with Python if not for uv. It’s that good.

          Before uv came along I was starting to write stuff in Go that I’d normally write in Python.

      • regularfry 26 minutes ago
        There's definitely a philosophical shift that you can observe happening over the last 12-15 years or so, where at the start you have the interpreter as the centre of the world and at the end there's an ecosystem management tool that you use to give yourself an interpreter (and virtual environments, and so on) per project.

        I think this properly kicked off with RVM, which needed to come into existence because you had this situation where the Ruby interpreter was going through incompatible changes, the versions on popular distributions were lagging, and Rails, the main reason people were turning to Ruby, was relatively militant about which interpreter versions it would support. Also, building the interpreter such that it would successfully run Rails wasn't trivial. Not that hard, but enough that a convenience wrapper mattered. So you had a whole generation of web devs coming up in an environment where the core language wasn't the first touchpoint, and there wasn't an assumption that you could (or should) rely on what you could apt-get install on the base OS.

        This is broadly an extremely good thing.

        But the critical thing that RVM did was that it broke the circular dependency at the core of the problem: it didn't itself depend on having a working ruby interpreter. Prior to that you could observe a sort of sniffiness about tools for a language which weren't implemented in that language, but RVM solved enough of the pain that it barged straight past that.

        Then you had similar tools popping up in other languages - nvm and leiningen are the first that spring to mind, but I'd also throw (for instance) asdf into the mix here - where the executable that you call to set up your environment has a '#!/bin/bash' shebang line.

        Go has sidestepped most of this because of three things: 1) rigorous backwards compatibility; 2) the simplest possible installation onramp; 3) being timed with the above timeline so that having a pre-existing `go` binary provided by your OS is unlikely unless you install it yourself. And none of those are true of Python. The backwards compatibility breaks in this period are legendary, you almost always do have a pre-existing Python to confuse things, and installing a new python without breaking that pre-existing Python, which your OS itself depends on, is a risk. Add to that the sniffiness I mentioned (which you can still see today on `uv` threads) and you've got a situation where Python is catching up to what other languages managed a decade ago.

        Again.

      • houzi 4 hours ago
        Do you think a non-python user would piece it together if the shebang line reveals what tool to use?
      • zahlman 33 minutes ago
        > you might find someone saying to use uv, but also potentially venv, poetry or hatch.

        This is sort of like saying "You might find someone saying to drive a Ford, but also potentially internal combustion engine, Nissan or Hyundai".

        • evilduck 26 minutes ago
          Only to those already steeped in Python. To an outsider they're all equally arbitrary non-descriptive words and there's not even obvious proper noun capitalization to tell apart a component from a tool brand.
          • zahlman 20 minutes ago
            It's always rather irritating to me that people make these complaints without trying to understand any of the under-the-hood stuff, because the ultimate conclusion is that it's somehow a bad thing that, on a FOSS project, multiple people tried to solve a problem concurrently.
    • embedding-shape 2 hours ago
      I've moved over mostly to uv too, using `uv pip` when needed but mostly sticking with `uv add`. But as soon as you start using `uv pip` you end up with all the drawbacks of `uv pip`, namely that whatever you pass after can affect earlier dependency resolutions too. Running `uv pip install dep-a` and then `... dep-b` isn't the same as `... dep-b` first and then `... dep-a`, or the same as `uv pip install dep-a dep-b` which coming from an environment that does proper dependency resolution and have workspaces, can be really confusing.

      This is more of a pip issue than uv though, and `uv pip` is still preferable in my mind, but seems Python package management will forever be a mess, not even the bandaid uv can fix things like these.

      • sieep 53 minutes ago
        Ive been away from python for awhile now, I was under the impression uv was somehow solving this dependency hell. Whats the benefit of using uv/pip together? Speed?
        • chuckadams 44 minutes ago
          `uv pip` is still uv, it's just uv's compatibility layer for pip.
    • t43562 1 hour ago
      ....but you have to be able to get UV and on some platforms (e.g. a raspberry pi) it won't build because the version of rust is too old. So I wrote a script called "pv" in python which works a bit like uv - just enough to get my program to work. It made me laugh a bit, but it works anywhere, well enough for my usecase. All I had to do was embed a primitive AI generated TOML parser in it.
      • zahlman 17 minutes ago
        > All I had to do was embed a primitive AI generated TOML parser in it.

        The standard recommendation for this is `tomli`, which became the basis of the standard library `tomllib` in 3.11.

    • zahlman 39 minutes ago
      There are really so many things about this point that I don't get.

      First off, in my mind the kinds of things that are "scripts" don't have dependencies outside the standard library, or if they do are highly specific to my own needs on my own system. (It's also notable that one of the advantages the author cites for Go in this niche is a standard library that avoids the need for dependencies in quick scripts! Is this not one of Python's major selling points since day 1?)

      Second, even if you have dependencies you don't have to learn differences between these tools. You can pick one and use it.

      Third, virtual environments are literally just a place on disk for those dependencies to be installed, that contains a config file and some stubs that are automatically set up by a one-liner provided by the standard library. You don't need to go into them and inspect anything if you don't want to. You don't need to use the activation script; you can just specify the venv's executable instead if you prefer. None of it is conceptually difficult.

      Fourth, sharing an environment for these quick scripts actually just works fine an awful lot of the time. I got away with it for years before proper organization became second nature, and I would usually still be fine with it (except that having an isolated environment for the current project is the easiest way to be sure that I've correctly listed its dependencies). In my experience it's just not a thing for your quick throwaway scripts to be dependent on incompatible Numpy versions or whatever.

      ... And really, to avoid ever having to think about the dependencies you provide dynamically, you're going to switch to a compiled language? If it were such a good idea, nobody would have thought of making languages like Python in the first place.

      And uh...

      > As long as the receiving end has the latest version of go, the script will run on any OS for tens of years in the future. Anyone who's ever tried to get python working on different systems knows what a steep annoying curve it is.

      The pseudo-shebang trick here isn't going to work on Windows any more than a conventional one is. And no, when I switched from Windows to Linux, getting my Python stuff to work was not a "steep annoying curve" at all. It came more or less automatically with acclimating to Linux in general.

      (I guess referring to ".pyproject" instead of the actually-meaningful `pyproject.toml` is just part of the trolling.)

      • kstrauser 18 minutes ago
        > Third, virtual environments are literally just a place on disk for those dependencies

        I had a recent conversation with a colleague. I said how nice it is using uv now. They said they were glad because they hated messing with virtualenvs so much that preferred TypeScript now. I asked them what node_modules is, they paused for a moment, and replied “point taken”.

        Uv still uses venvs because it’s the official way Python stores all the project packages in one place. Node/npm, Go/go, and Rust/cargo all do similar things, but I only really here people grousing about Python’s version, which as you say, you can totally ignore and never ever look at.

    • tgv 2 hours ago
      Won't those dependencies then be global? With potential conflicts as a result?
      • auxym 2 hours ago
        uv uses a global cache but hardlinks the dependencies for your script into a temp venv that is only for your script, so its still pretty fast.
      • stephenlf 2 hours ago
        Nope! uv takes care of that. uv is a work of art.
        • tgv 2 hours ago
          Then I should seriously take a look at it. I figured it was just another package manager.
  • PaulRobinson 4 hours ago
    Mad genius stuff, this.

    However... scripting requires (in my experience), a different ergonomic to shippable software. I can't quite put my finger on it, but bash feels very scriptable, go feels very shippable, python is somewhere in the middle, ruby is closer to bash, rust is up near go on the shippable end.

    Good scripting is a mixture of OS-level constructs available to me in the syntax I'm in (bash obviously is just using OS commands with syntactic sugar to create conditional, loops and variables), and the kinds of problems where I don't feel I need a whole lot of tooling: LSPs, test coverage, whatever. It's languages that encourage quick, dirty, throwaway code that allows me to get that one-off job done the guy in sales needs on a Thursday so we can close the month out.

    Go doesn't feel like that. If I'm building something in Go I want to bring tests along for the ride, I want to build a proper build pipeline somewhere, I want a release process.

    I don't think I've thought about language ergonomics in this sense quite like this before, I'm curious what others think.

    • dingdingdang 4 hours ago
      Talking about Python "somewhere in the middle" - I had a demo of a simple webview gtk app I wanted to run on vanilla Debian setup last night.. so I did the canonical-thing-of-the-month and used uv to instantiate a venv and pull the dependencies. Then attempted to run the code.. mayhem. Errors indicating that the right things were in place but that the code still couldn't run (?) and finally Python Core Dumped.. OK. This is (in some shape or form) what happens every single time I give Python a fresh go for an idea. Eventually Golang is more verbose (and I don't particularly like the mod.go system either) but once things compile.. they run. They don't attempt running or require xyz OS specific hack.
      • fireflash38 2 hours ago
        Gtk makes that simple python program way more complex since it'll need more than pure-python dependencies.

        It's really a huge pain point in python. Pure python dependencies are amazingly easy to use, but there's a lot of packages that depend on either c extensions that need to be built or have OS dependencies. It's gotten better with wheels and manylinux builds, but you can still shoot your foot off pretty easily.

      • skeledrew 1 hour ago
        I'm pretty sure the gtk dependencies weren't built by Astral, which, yes, unfortunately means that it won't always just work, as they streamline their Python builds in... unusual ways. A few months ago I had a similar issue running a Tkinter project with uv, then all was well when I used conda instead.
      • zelphirkalt 2 hours ago
        How were the dependencies specified? What kind of files were provided for you to instantiate the venv?
      • logicallee 3 hours ago
        I haven't had the same issue with anaconda. Give it a try.
        • dns_snek 3 hours ago
          I've had similar issues with anaconda, once upon a time. I've hit a critical roadblock that ruined my day with every single Python dependency/environment tool except basic venv + requirements.txt, I think. That gets in the way the least but it's also not very helpful, you're stuck with requirements.txt which tends to be error-prone to manage.
    • skybrian 2 hours ago
      Maybe the ergonomics of writing code is less of a problem if you have a quick way of asking an LLM to do the edits? We can optimize for readability instead.

      More specifically, for the readability of code written by an LLM.

    • cl3misch 2 hours ago
      > bash obviously is just using OS commands with syntactic sugar

      No, bash is technically not "more" OS than e.g. Python. It just happens that bash is (often) the default shell in the terminal emulator.

      • xg15 2 hours ago
        Have to disagree, "technically" yes, both are interpreted languages, but the ergonomics and mental overhead of doing certain things are wildly different:

        In python, doing math or complex string or collection operations is usually a simple oneliner, but calling shell commands or other OS processes requires fiddling with the subprocess module, writing ad-hoc streaming loops, etc - don't even start with piping several commands together.

        Bash is the opposite: As long as your task can be structured as a series of shell commands, it absolutely shines - but as soon as you require custom data manipulation in any form, you'll run into awkward edge cases and arbitrary restrictions - even for things that are absolutely basic in other languages.

        • t43562 1 hour ago
          The subprocess module is horrendous but even if it was great bash is simpler. I just think about trying to create a pipe of processes in python without the danger of blocking.
      • skeledrew 1 hour ago
        I love Python and dislike Bash, but just look at the difference between listing a folder in Bash vs Python, for example.
  • chrisweekly 9 minutes ago
    Related tangent: I recently learned about Mise^1 -- a tool for managing multiple language runtime versions. It might ease some of the python environment setup/mgmt pains everyone complains about. It apparently integrates with uv, and can do automatic virtualenv activation....

    1. https://mise.jdx.dev/lang/python.html

    via https://gelinjo.hashnode.dev/you-dont-need-nvm-sdkman-pyenv-...

  • codelikeawolf 12 minutes ago
    > Did you (rightfully) want to tear your eyes out when some LLM suggested that you script with .mjs?

    I respectfully disagree with this sentiment. JS is a fantastic Python replacement for scripts. Node.js has added all kinds of utility functions that help you write scripts without needing external dependencies. Bun, Deno, and Node.js can execute TS files (if you want to bring types into the mix). All 3 runtimes are sufficiently performant. If you do end up needing external dependencies, they're only a package.json away. I write all my scripts in JS files these days.

  • fsmv 1 hour ago
    I made one of these too! I decided not to use // because I use gofmt auto formatting in my editor and it puts a space between the // and the usr. This one isn't changed by gofmt:

        /*?sr/bin/env go run "$0" "$@"; exit $? #*/
  • petercooper 38 minutes ago
    Cute trick! I pointlessly wondered if I could make it work with Ruby and you kinda can, if you can tolerate a single error message before the script runs (sadly # comments don't work as shells consider them comments too):

        =begin
        ruby $0; exit
        =end
    
        puts "Hello from Ruby"
    
    Not immediately useful, but no doubt this trick will pop up at some random moment in the future and actually be useful. Very basic C99 too, though I'm not sure I'd want to script with it(!):

        //usr/bin/cc $0 && ./a.out && exit
  • g947o 1 hour ago
    While you are at it, might as well do this for C++ or assembly. You hate scripting so much and would rather go to great lengths to use a complied language and throw away all the benefits of a scripting language and scripting itself, just because you don't like the language, not because of technical merit. Congratulations, you just wasted yourself many hours of precious time.

    > The price of convenience is difficulties to scale

    Of course, they never scale. The moment you start thinking about scaling, you should stop writing code as throwaway scripts but build them properly. That's not an argument to completely get rid of Python or bash. The cost of converting Python code to Go is near zero these days if there is a need to do so. Enough has been said about premature optimization.

    > Anyone who's ever tried to get python working on different systems knows what a steep annoying curve it is.

    If you need 10 libraries of certain versions to run a few lines of Python code, nobody calls that a script anymore. It becomes a proper project that requires proper package management, just like Go.

    • BobbyJo 1 hour ago
      There is a much larger gap in language ergonomics between python and C++ than between python and golang. Compile time and package management being some of the major downsides to C++.

      "You'd rather drive a compact car than an SUV? Might as well drive a motorcycle then!"

  • flufluflufluffy 3 hours ago
    I don’t really understand the initial impetus. I like scripting in Python. That’s one of the things it’s good at. You can extremely quickly write up a simple script to perform some task, not worrying about types, memory, yada yada yada. I don’t like using Python as the main language for a large application.
    • graemep 2 hours ago
      It seems to be Linux specific (does it even work on other unix like OSes?) and Linux usually has a system Python which is reasonably stable for things you need scripting for, whereas this requires go to be installed.

      You could also use shell scripting or Python or another scripting language. While Python is not great at backward compatibility most scripts will have very few issues. Shell scripts are backward compatible as are many other scripting languages are very backward compatible (e.g. TCL) and they areG more likely to be preinstalled. If you are installing Go you could just install uv and use Python.

      The article does say "I started this post out mostly trolling" which is part of it, but mostly the motivation would be that you have a strong preference for Go.

    • mr_toad 2 hours ago
      I love scripting in Python too. I just hate trying to install other people’s scripts.
      • zahlman 13 minutes ago
        > I just hate trying to install other people’s scripts.

        This notion is still strange to me. Just... incompatible with how I understand the term "script", I guess.

      • flanked-evergl 2 hours ago
        If they use https://packaging.python.org/en/latest/specifications/inline... then it becomes a breeze to run with uv. Not even a thing.
        • hu3 53 minutes ago
          but then you need uv

          it's not as portable

          • networked 36 minutes ago
            Inline script metadata itself is not tied to uv because it's a Python standard. I think the association between the two comes from people discovering ISM through uv and from their simultaneous rise.

            pipx can run Python scripts with inline script metadata. pipx is implemented in Python and packaged by Linux distributions, Free/Net/OpenBSD, Homebrew, MacPorts, and Scoop (Windows): https://repology.org/project/pipx/versions.

            • zahlman 12 minutes ago
              Yes, many things can use inline script metadata.

              But a script only has one shebang.

    • Kuinox 2 hours ago
      You do have to worry about types, you always do. You have to know, what did this function return, what can you do with it.

      When you know well the language, you dont need to search for this info for basic types, because you remember them.

      But that's also true for typed languages.

      • phantasmish 20 minutes ago
        This is more than just trivially true for Python in a scripting context, too, because it doesn’t do things like type coercion that some other scripting languages do. If you want to concat an int with a string you’ll need to cast the int first, for example. It also has a bunch of list-ish and dict-ish built in types that aren’t interchangeable. You have to “worry about types” more in Python than in some of its competitors in the scripting-language space.
  • esjeon 2 hours ago
    Expected a rant, got a life-pro-tip. Enough for a good happy new year.

    That said, we can abuse the same trick for any languages that treats `//` as comment.

    List of some practical(?) languages: C/C++, Java, JavaScript, Rust, Swift, Kotlin, ObjC, D, F#, GLSL/HLSL, Groovy

    Personally, among those languages, GLSL sounds most interesting. A single-GLSL graphics demo is always inspiring. (Something like https://www.shadertoy.com/ )

    Also, let’s not forget that we can do something similar using block comment(`/* … */`). An example in C:

    /*/../usr/bin/env gcc "$0" "$@"; ./a.out; rm -vf a.out; exit; */

    #include <stdio.h>

    int main() { printf("Hello World!\n"); return 0; }

    • frizlab 2 hours ago
      For Swift there’s even a project[1] that allows running scripts that have external dependencies (posting the fork because the upstream is mostly dead).

      I think it’s uv’s equivalent, but for Swift.

      (Also Swift specifically supports an actual shebang for Swift scripts.)

      [1] https://github.com/xcode-actions/swift-sh

    • kibwen 34 minutes ago
      You don't need to abuse comments like this for Rust, because it supports shebangs directly.
  • llmslave2 4 hours ago
    I love it. I'm using Go to handle building full stack javascript apps, which actually works great since esbuild can be used directly inside a Go program. The issue is that it's a dependency, so I settled for having a go mod file and running it directly with Go. If somehow these dependencies could be resolved without an explicit module configured (say, it was inline in the go file itself) it would be perfect. Alas, it will probably never happen.

    That being said...use Go for scripting. It's fantastic. If you don't need any third party libraries this approach seems really clean.

    • ahartmetz 4 hours ago
      [flagged]
      • dangoodmanUT 2 hours ago
        dwight shrute detected
      • llmslave2 4 hours ago
        Yes. Yes, I'm doing all of that with Javascript :P
      • mstipetic 4 hours ago
        Don't be that guy.
        • ahartmetz 4 hours ago
          I am going to be that guy.

          I make computers do things, but I never act like my stuff is the only stuff that makes things happen. There is a huge software stack of which my work is just the final pieces.

          • mstipetic 4 hours ago
            The term "full stack" has a widely well understood meaning, you're being pedantic
            • SunlitCat 3 hours ago
              The problem with calling it “full stack” (even if it has a widely understood meaning) is that it implicitly puts the people doing the actual lower-level work on a pedestal. It creates the impression that if this is already “full stack,” then things like device drivers, operating systems, or foundational libraries must be some kind of arcane magic reserved only for experts, which they aren’t.

              The term “full stack” works fine within its usual context, but when viewed more broadly, it becomes misleading and, in my opinion, problematic.

              • ahartmetz 3 hours ago
                Or, alternatively, it ignores and devalues the existence of these parts. In both cases, it's a weird "othering" of software below a certain line in the, ahem, full stack.
            • ahartmetz 3 hours ago
              It doesn't for me and I don't think that my subculture of computing uses similarly myopic terms.
              • konart 2 hours ago
                >It doesn't for me

                And it's okay. It doesn't mean it should be this way for everyone else.

                It is pretty common (and been so for at least two decades) for web devs to differentiate like so: backend, frontend or both. This "both" part almost always is replaced by "full stack".

                When people say this they just mean they do both parts of a web app and have no ill will or neglect towards systems programmers or engineers working on a power plant.

              • llmslave2 3 hours ago
                Where did your subculture come from, Pedanticville?
                • ahartmetz 3 hours ago
                  Mostly not web-based software, written in compiled languages
                  • flir 1 hour ago
                    A grown-up ;)
          • bheadmaster 3 hours ago
            I agree with you in sentiment - the term "full-stack" is odd and a little too grandiose for its meaning.

            But it is already established in the industry, and fighting it is unlikely to yield any positive outcomes.

  • marifjeren 1 hour ago
    > don't want to have virtual environments and learn what the difference between pip, poetry and uv is

    Oh come on, it's easy:

    Does the project have a setup.py? if so, first run several other commands before you can run it. python -m venv .venv && source .venv/bin/activate && pip install -e .

    else does it have a requirements.txt? if so python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt

    else does it have a pyproject.toml? if so poetry install and then prefix all commands with poetry run ...

    else does it have a pipfile? pipenv install and then prefix all commands with pipenv run ...

    else does it have an environment.yml? if so conda env create -f environment.yml and then look inside the file and conda activate <environment_name>

    else does it have a uv.ock? then uv sync (or uv pip install -e .) and then prefix commands with uv run.

  • magicalhippo 4 hours ago
    You can do the same[1] with .Net Core for those of us who like that.

    [1]: https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals...

    • rr808 4 hours ago
      dotnet was always really good for this. There were a bunch of third party tools that have done this since the 90s like toolsack.

      I think Java can run uncompiled text scripts now too

  • rtpg 2 hours ago
    You don't even need to end the file in `.go` or the like when using shebangs, and any self-respecting editor will be good at parsing out shebangs to identify file types (... well, Emacs seems to do it well enough for me)

    no need to name your program foo.go when you could just name it foo

  • age123456gpg 4 hours ago
    Official stance about supporting interpreter mode for the reference https://github.com/golang/go/issues/24118
  • w4rh4wk5 4 hours ago
    Back in the days, I've seen that with C files, which are compiled on the fly to a temporary file an run.

    Something like //usr/bin/gcc -o main "$0"; ./main "$@"; exit

    • ernst_klim 4 hours ago
      Tcc even supports that with `#!/usr/local/bin/tcc -run`, although I don't understand people who use c or go for "scripting", when python, ruby, TCL or perl have much superior ergonomics.
      • w4rh4wk5 4 hours ago
        This was a relatively old project that used a C program as build system / meta generator. All you needed was a working C compiler (and your shell to execute the first line). From there, it built and ran a program that generated various tables and some source code, followed by compiling the actual program. The final program used a runtime reflection system, which was set up by the generated tables and code from the first stage.

        The main reason was to do all this without any dependencies beyond a C compiler and some POSIX standard library.

  • itopaloglu83 1 hour ago
    > Sidetrack: I actually looked up what the point of arg0 even is since I failed to find any usecases some months back and found this answer.

    I think arg0 was always useful especially when developing multifunctional apps like busybox that changes its behavior depending on the name it was executed as.

  • jas39 3 hours ago
    May I...

    augroup fix autocmd! autocmd BufWritePost *.go \ if getline(1) =~# '^// usr/bin/' \ | call setline(1, substitute(getline(1), '^// ', '//', '')) \ | silent! write \ | endif augroup END

  • chrismorgan 4 hours ago
    One suggestion: change `exit` to `exit $?` so an exit code is passed back to the shell.
  • networked 2 hours ago
    You can use https://github.com/erning/gorun as a Go script runner. It lets you embed `go.mod` and `go.sum` and have dependencies in Go scripts. This is more verbose than Python's inline script metadata and requires manual management of checksums. gorun caches built binaries, so scripts start quickly after the first time.

    Example:

      #! /usr/bin/env gorun
      //
      // go.mod >>>
      // module foo
      // go 1.22
      // require github.com/fatih/color v1.16.0
      // require github.com/mattn/go-colorable v0.1.13
      // require github.com/mattn/go-isatty v0.0.20
      // require golang.org/x/sys v0.14.0
      // <<< go.mod
      //
      // go.sum >>>
      // github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
      // github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
      // github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
      // github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
      // github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
      // github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
      // github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
      // golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
      // golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
      // golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
      // golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
      // <<< go.sum
    
      package main
    
      import "github.com/fatih/color"
    
      func main() {
          color.Green("Hello, world!")
      }
    
    The shebang line can be replaced for compatibility with standard Go tooling:

      /// 2>/dev/null ; gorun "$0" "$@" ; exit $?
      //
      // go.mod >>>
      // ...
    • karel-3d 1 hour ago
      I was looking for something like this a few times! great
  • throw-12-16 5 hours ago
    I've been meaning to port some dotfiles utils over to go, I think I'll give this a shot.
  • xg15 2 hours ago
    So the entire reason why this is not a "real" shebang and instead takes the roundtrip through the shell is because the Go runtime would trip over the # character?

    I think this points to some shortcomings of the shebang mechanism itself: That it expects the shebang line to be present and adhering a specific structure - but then passes the entire file with the line to the interpreter where the interpreter has to process (and hopefully ignore) the line again.

    I know that situations where one piece of text is parsed by multiple different systems are intellectually interesting and give lots of opportunities for cleverness - but I think the straightforward solution would be to avoid such situations.

    So maybe the linux devs should consider adding a new form for the shebang where the first line is just stripped before passing the file contents to the interpreter.

    • wyufro 1 hour ago
      It doesn't pass the file contents at all, it passes the file path.
  • emersion 3 hours ago
    The following would probably be more portable:

        ///usr/bin/env go run "$0" "$@"; exit
    
    Note, the exit code isn't passed through due to: https://github.com/golang/go/issues/13440
    • incognito124 3 hours ago
      To quote the blog in question:

      > How true this is, is a topic I dare not enter.

  • liveoneggs 2 hours ago
    what's even cooler is when the language comes with first class support for this: https://www.erlang.org/docs/18/man/escript

    Or the venerable https://babashka.org/

  • Zababa 35 minutes ago
    >This second method is, by the way, argued to increase compatibility as we utilize env to locate bash, which may not be located at /bin/bash. How true this is, is a topic I dare not enter.

    At least it seems important on NixOS, I had to rewrite a few shebangs on some scripts that used /bin/bash and didn't work on NixOS.

  • jxbdbrhcb 46 minutes ago
    argv0 is very necessary for use cases like busybox
  • api 2 hours ago
    Tangent but... I kinda like the Python language. What I don't like about Python is the way environments are managed.

    This is something I generally believe, but I think it's particularly important for things like languages and runtimes: the idea of installing things "on" the OS or the system needs to die.

    Per-workspace or per-package environment the way Go, Rust, etc. does it is correct. Installing packages globally is wrong.

    There should not be such a thing as "globally." Ideally the global OS should be immutable or nearly so, with the only exception being maybe hardware driver stuff.

    (Yes I know there's stuff like conda, but that's yet another thing to fix a fundamentally broken paradigm.)

  • rubymamis 1 hour ago
    What about Mojo?
    • lgas 1 hour ago
      What about it?
  • avidphantasm 2 hours ago
    Now try to call some C++ code from your Go script…
  • flanked-evergl 2 hours ago
    Using `uv` with python is significantly safer and better. At least you get null safety. Sure, you can't run at the speed of light, but at least you can have some decent non-halfarsed-retrofitted type checking in your script.
    • tgv 2 hours ago
      I think you're mistaking Go for some other language.
  • solumos 4 hours ago
    > I started this post out mostly trolling, but the more I've thought about it's not a terrible idea.

    I feel like this is the unofficial Go motto, and it almost always ends up being a terrible idea.

    • hu3 5 minutes ago
      for more terrible ideas in 2026 then!
  • assanineass 2 hours ago
    [dead]
  • wiseowise 4 hours ago
    [flagged]