How do you handle packages? I want scripts to a be a single file with a shebang, not a repo with a requirements.txt that I need to run in a venv. To me, this is the biggest blocker to using Python for any non-trivial scripting (which is precisely the kind where I wouldn't want to use bash), but I'd like to know how others deal with it.
C# scripts let you reference packages in a comment at the top of the file, for example:
As someone who writes a lot of python, I love uv, but isn't on nearly every system like python is, which is one of the arguments for using python here in the first place
What can you do with bash that isn't in the stdlib of python?
Generally the only nontrivial scripting I ever do is associated with a larger project, so I often already have a pyproject.toml and a UV environment, and I just add the dependencies to the dev group.
Well, that's kind of what I mean. For scripts in a python project, you can freely use whatever packages you need. But for one-off scripts, if you need bs4 or something, you're screwed. Either your script now has external dependencies or it requires special tooling.
It just feels strange that C# of all languages is now a better scripting tool than Python, at least out of the box. I did notice uv has exactly the feature I'm looking for, though it's obviously third-party:
Is everyone just using uv now instead of pip, perhaps? Or is just another alongside pipenv, conda, poetry, etc.? (Python's not my main these days, so I'm out of the loop.)
I don't understand. To return to GP's point, what can you do in bash that you can't do in Python? Said in another way, what does bash offer that you would need to tackle with a dependency in Python? My understanding is that there is no such thing, and accordingly, you can still end up with something that is better than bash if you just use Python and call out to other tools with subprocess.
There's bash. Then you need better loops/conditionals and more usable structures. That's when one should think of using a scripting language instead. I think the parent goes too far after that and what he's talking about is not something bash can do (well).
That said, a lot of very complicated things are actually written in bash. Distrobox I think is for example.
>That said, a lot of very complicated things are actually written in bash. Distrobox I think is for example.
They're only complicated BECAUSE they're written in bash. If they were written in Python they would be much less complicated, more modular, able to use many existing industrial strength well tested python modules instead of rolling their own ad-hoc ones, and much easier to maintain.
Whoa! This is a revelation. I already loved Nix and used nix-shell extensively, but this is the missing piece: fully reproducible Python scripts without compromise.
Or install direnv and put your dependencies into a shell.nix, setup the bash hook according the manual, create the .envrc with the content "use nix". Then type "direnv allow".
Then you can do e.g. use other persons python scripts without modifying their shebang.
Isn't the fact that bash doesn't have a wonderful ecosystem of reusable modules a much more enormous insurmountable problem than the fact that you have to install python modules? You're really missing the forest for the trees.
Not only does bash not have a module system like python, or a vast ecosystem of modules like python, but also that it's much too weak and brittle a language to implement most of those modules that Python has, and can't even call native code libraries directly.
Even with just its standard built in "batteries included" libraries and no extension modules or native code modules, Python is still much more powerful than bash and easier to code and maintain.
If you're complaining about having to install Python modules, you're usually already doing something that's impossible or incredibly difficult to do in bash anyway.
Even something as simple and essential as fetching files via http or parsing json. Bash has to call out to other programs to do that, but you have to install those programs too, and while Python can certainly call out to curl or wget or jq, it doesn't have to, since it has all that and more built in.
There really is no comparison, because bash loses along so many dimensions at once compared to Python.
I think it is the fact that python packaging has been problematic for some time. setuptools/easy_install, pip/pipx, poetry, conda, uv all promise they will be the thing that "fixes" it
Ok tbh bash uses the system package manager to install command-line utilities, and using the system package manager for python packages HAS been tried, and the parallel use of system packaging and independent package managers is part of why python package distribution is such a mess.
Odd, I don't see any mention of subprocess.run, the workhorse of python scripting.
Quick rundown for the unfamiliar:
Give it a command as a list of strings (e.g., subprocess.run(["echo", "foo"]).)
It takes a bunch of flags, but the most useful (but not immediately obvious) ones are:
check=True: Raise an error if the command fails
capture_output=True: Captures stdout/stderr on the CompletedProcess
text=True: Automatically convert the stdout/stderr bytes to strings
By default, subprocess.run will print the stdout/stderr to the script's output (like bash, basically), so I only bother with capture_output if I need information in the output for a later step.
Also `asyncio.subprocess`, which lets you manage multiple concurrently running commands. Very handy if you need to orchestrate several commands together.
The Python stdlib does not get enough credit. People complain about things like how its http client is dated and slow, but its pretty amazing that it’s just right there if you need it, no external dependencies needed. And it’s sitting right next to difflib, graphlib, pathlib, struct, glob, tkinter, and dozens of others. Sure, every one of these is limited individually, but those limitations are stable and well understood!
If a script is simple - I use posix sh + awk, sed, etc.
But if a script I write needs to use arrays, sets, hashtable or processes many files - I use Nim[0]. It's a compiled systems-programming language that feels like a scripting language:
- Nim is easy to write and reads almost like a pseudocode.
- Nim is very portable language, runs almost anywhere C can run (both compiler and programs).
- `nim r script.nim` to compile and run (cached on subsequent runs) or use a shebang `#!/bin/env -S nim r`
- Nim programs are fast to compile (use debug mode and tcc compiler for almost instant compile times)
- Nim scripts run very fast <10ms (something that was very annoying to me with bash and Python)
- good chances you don't need external dependencies, because stdlib is batteries included and full of goodies.
- if you need external deps - just statically link them and distribute a cross-compiled binary (use zigcc[1] for easy Nim cross-compilation).
I've never liked shell scripting. Last year, I switched my build system of a Rust project over to Python (Cargo is actually quite limited as a build system). For a newer project, I'm using Rust itself with the XTask pattern. I'm not sure if I prefer the Python or Rust approach yet.
I have been converting a lot of my makefiles to pyinvoke and fabric and it makes things so much easier to manage than bash or make. Don't know why I held on for so long.
Pretty much anything longer then a throwaway one liner I write in python.
Would be cool if python had a pipe operator though.
The back ticks in ruby is pretty ergonomic too. Wish python had a simpler way to run commands. Kind of tedious to look up subprocess run arguments and also break things up into arrays.
nushell (https://www.nushell.sh/) is essentially perfect for this use case! i use it rather than posix(y) shells for most projects where id normally reach for python.
How do you handle packages? I want scripts to a be a single file with a shebang, not a repo with a requirements.txt that I need to run in a venv. To me, this is the biggest blocker to using Python for any non-trivial scripting (which is precisely the kind where I wouldn't want to use bash), but I'd like to know how others deal with it.
C# scripts let you reference packages in a comment at the top of the file, for example:
https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-...
You can specify requirements at the top of file and uv can run the script after automatically installing the dependencies.
https://avilpage.com/2025/04/learn-python-uv-in-100-seconds....
This works really well in my experience, but it does mean you need to have a working internet connection the first time you run the script.
Then: It manages a disposable hidden virtual environment automatically, via a very fast symlink-based caching mechanism.You can also add a shebang line so you can execute it directly:
Then:I wish env -S was more portable. It's a newer feature of the coreutils env implementation and isn't supported elsewhere afaik.
FreeBSD 6.0 added 'env -S'. They have adopted a few different GNU inspired options recently, which I am happy about.
As someone who writes a lot of python, I love uv, but isn't on nearly every system like python is, which is one of the arguments for using python here in the first place
What can you do with bash that isn't in the stdlib of python?
Generally the only nontrivial scripting I ever do is associated with a larger project, so I often already have a pyproject.toml and a UV environment, and I just add the dependencies to the dev group.
Well, that's kind of what I mean. For scripts in a python project, you can freely use whatever packages you need. But for one-off scripts, if you need bs4 or something, you're screwed. Either your script now has external dependencies or it requires special tooling.
It just feels strange that C# of all languages is now a better scripting tool than Python, at least out of the box. I did notice uv has exactly the feature I'm looking for, though it's obviously third-party:
https://docs.astral.sh/uv/guides/scripts/#declaring-script-d...
Is everyone just using uv now instead of pip, perhaps? Or is just another alongside pipenv, conda, poetry, etc.? (Python's not my main these days, so I'm out of the loop.)
I don't understand. To return to GP's point, what can you do in bash that you can't do in Python? Said in another way, what does bash offer that you would need to tackle with a dependency in Python? My understanding is that there is no such thing, and accordingly, you can still end up with something that is better than bash if you just use Python and call out to other tools with subprocess.
There's bash. Then you need better loops/conditionals and more usable structures. That's when one should think of using a scripting language instead. I think the parent goes too far after that and what he's talking about is not something bash can do (well).
That said, a lot of very complicated things are actually written in bash. Distrobox I think is for example.
>That said, a lot of very complicated things are actually written in bash. Distrobox I think is for example.
They're only complicated BECAUSE they're written in bash. If they were written in Python they would be much less complicated, more modular, able to use many existing industrial strength well tested python modules instead of rolling their own ad-hoc ones, and much easier to maintain.
UV is taking over really fast, it seems to be much more popular any other option.
I suspect conda still has some market share too but I've never needed it.
It's amazing what happens when something just works.
Nix allows you to do this with any language and required dependency: https://wiki.nixos.org/wiki/Nix-shell_shebang
Whoa! This is a revelation. I already loved Nix and used nix-shell extensively, but this is the missing piece: fully reproducible Python scripts without compromise.
Or install direnv and put your dependencies into a shell.nix, setup the bash hook according the manual, create the .envrc with the content "use nix". Then type "direnv allow".
Then you can do e.g. use other persons python scripts without modifying their shebang.
https://peps.python.org/pep-0723/, e.g.:
what can you do with bash that you cannot do with the python standard library and shelling out?
Isn't the fact that bash doesn't have a wonderful ecosystem of reusable modules a much more enormous insurmountable problem than the fact that you have to install python modules? You're really missing the forest for the trees.
Not only does bash not have a module system like python, or a vast ecosystem of modules like python, but also that it's much too weak and brittle a language to implement most of those modules that Python has, and can't even call native code libraries directly.
Even with just its standard built in "batteries included" libraries and no extension modules or native code modules, Python is still much more powerful than bash and easier to code and maintain.
If you're complaining about having to install Python modules, you're usually already doing something that's impossible or incredibly difficult to do in bash anyway.
Even something as simple and essential as fetching files via http or parsing json. Bash has to call out to other programs to do that, but you have to install those programs too, and while Python can certainly call out to curl or wget or jq, it doesn't have to, since it has all that and more built in.
There really is no comparison, because bash loses along so many dimensions at once compared to Python.
What is wrong with writing a short wrapper in bash to activate a conda env before running the script? Too unsexy?
> How do you handle packages?
The same way you handle them with bash?
Install them?
What are we talking about here?
I think it is the fact that python packaging has been problematic for some time. setuptools/easy_install, pip/pipx, poetry, conda, uv all promise they will be the thing that "fixes" it
What does Bash use for its packaging?
Use that.
Ok tbh bash uses the system package manager to install command-line utilities, and using the system package manager for python packages HAS been tried, and the parallel use of system packaging and independent package managers is part of why python package distribution is such a mess.
Odd, I don't see any mention of subprocess.run, the workhorse of python scripting.
Quick rundown for the unfamiliar:
Give it a command as a list of strings (e.g., subprocess.run(["echo", "foo"]).)
It takes a bunch of flags, but the most useful (but not immediately obvious) ones are:
By default, subprocess.run will print the stdout/stderr to the script's output (like bash, basically), so I only bother with capture_output if I need information in the output for a later step.Also `asyncio.subprocess`, which lets you manage multiple concurrently running commands. Very handy if you need to orchestrate several commands together.
> Python is installed on pretty much every machine
> Python 3 is installed on basically every machine out there.
> Python will work the same on all the machines you run your script on
No, no, and no.
More like, "no, but installation is easy", "yes, if the machine is safe", "depends on what you do"
The Python stdlib does not get enough credit. People complain about things like how its http client is dated and slow, but its pretty amazing that it’s just right there if you need it, no external dependencies needed. And it’s sitting right next to difflib, graphlib, pathlib, struct, glob, tkinter, and dozens of others. Sure, every one of these is limited individually, but those limitations are stable and well understood!
If a script is simple - I use posix sh + awk, sed, etc.
But if a script I write needs to use arrays, sets, hashtable or processes many files - I use Nim[0]. It's a compiled systems-programming language that feels like a scripting language:
- Nim is easy to write and reads almost like a pseudocode.
- Nim is very portable language, runs almost anywhere C can run (both compiler and programs).
- `nim r script.nim` to compile and run (cached on subsequent runs) or use a shebang `#!/bin/env -S nim r`
- Nim programs are fast to compile (use debug mode and tcc compiler for almost instant compile times)
- Nim scripts run very fast <10ms (something that was very annoying to me with bash and Python)
- good chances you don't need external dependencies, because stdlib is batteries included and full of goodies.
- if you need external deps - just statically link them and distribute a cross-compiled binary (use zigcc[1] for easy Nim cross-compilation).
[0] - https://nim-lang.org
[1] - https://github.com/enthus1ast/zigcc
I've never liked shell scripting. Last year, I switched my build system of a Rust project over to Python (Cargo is actually quite limited as a build system). For a newer project, I'm using Rust itself with the XTask pattern. I'm not sure if I prefer the Python or Rust approach yet.
> By the way, don’t add a comma after the elements in the list, ...
Python:
Same, use Javascript for Scripting. https://github.com/gutenye/script.js
Xonsh is perfect for this: https://xon.sh
I have been converting a lot of my makefiles to pyinvoke and fabric and it makes things so much easier to manage than bash or make. Don't know why I held on for so long.
Dupe: https://news.ycombinator.com/item?id=46176113
Pretty much anything longer then a throwaway one liner I write in python.
Would be cool if python had a pipe operator though.
The back ticks in ruby is pretty ergonomic too. Wish python had a simpler way to run commands. Kind of tedious to look up subprocess run arguments and also break things up into arrays.
nushell (https://www.nushell.sh/) is essentially perfect for this use case! i use it rather than posix(y) shells for most projects where id normally reach for python.
Weren't we already?
Python for scripting honestly is Xonsh :)