A
Andrew Moffat
amoffat.github.io · Personal blog · on HN since 2013
Andrew Moffat writes about his open source projects, including the Python sh module and the supertag tag-based filesystem, plus programming essays.
What HN saysCommenters praise the sh module as excellent for using shell commands and pipes from Python, and call the supertag FAQ exceptionally well put together.
50HN people shared it
44linked it in comments
13stories submitted
80story points
3 months agolast shared
2013people per year2026
Most-shared posts
- 1Shell Scripting support for Python39 people · 12 points · first shared 2013 · discussion on HN
- 2Show HN: Reimagine the File System5 people · 51 points · first shared 2020 · 13 comments on HN
- 3Vetted AI code is hard to justify3 people · 3 points · first shared 2026 · 2 comments on HN
- 4Faq3 people · first shared 2017
- 5Faq2 people · first shared 2022
- 6Why is it called a Fibonacci Heap?1 people · 5 points · first shared 2018 · discussion on HN
- 7Show HN: Solve the Travelling Salesman Problem with the GPU1 people · 3 points · first shared 2017 · discussion on HN
- 8WebGL Solver for the Travelling Salesman Problem1 people · 3 points · first shared 2017 · 2 comments on HN
- 9Travelling Salesman solver with WebGL1 people · 2 points · first shared 2017 · discussion on HN
- 10Fight the Bug, Not the Tools1 people · 1 points · first shared 2019 · discussion on HN
- 11Piping1 people · first shared 2022
- 12Index1 people · first shared 2022
What HN people wrote when they linked it
yjftsjthsd-h · 2022-03-26
On the contrary, I am 100% open to suggestions that BASH sucks. (Personally, I would have picked the inadequacies of `set -e` as my favorite ... unfortunate aspect.) My objection was very narrow: this specific article does a poor job at saying why shell sucks, and a worse job still at presenting Python as a superior alternative. That's not to say that good reasons to use something else don't exist, and it's not even to say that Python can't be that alternative. (Your sibling comments suggesting xonsh and https://amoffat.github.io/sh/ paint a fairly compelling way to actually move to python without losing the advantages of shell, for instance.)
stickfigure · 2022-01-24
Wow, I did not expect that! Fantastic, I'll check this out when I get a few spare cycles.
EDIT: Couldn't wait. This is an exceptionally well put-together FAQ, explaining the design constraints: https://amoffat.github.io/supertag/faq.html
imiric · 2021-04-04
Great, would that work with pipes and redirections too? At that point you might as well use sh[1] which is a more advanced abstraction. My issue with these approaches is that you'll inevitably hit a bug or limitation where just using a shell language would've been easier to maintain and more portable.
Python has its uses, but replacing shell scripts is not one of them IMO. It it was then the problem didn't need to be a shell script to begin with (doesn't shell out often, needs complex data structures, etc.).
[1]: https://amoffat.github.io/sh/
Shared404 · 2021-01-01
I'm loving this trend to do more things with filesystems.
There was https://amoffat.github.io/supertag/ [,] which I'm intending to use in my filesharing sftp server, and now this, which seems like something that exposes functionality from a web browser that I would love.
lars512 · 2019-04-13
The sh module is really excellent, and it lets you take the best parts of bash (the external commands, pipes) and ditch the bad parts (string handling, general programming). I think it’s what you’re looking for.
https://amoffat.github.io/sh/
masklinn · 2017-04-23
Namespaces are a honking great idea, let's do more of those!
Alternatively there's always the option of using something like sh[0] and just shelling out to the existing utilities, if you don't mind the portability loss.
[0] https://amoffat.github.io/sh/
goffi · 2023-01-28
`sh` is great for that: https://amoffat.github.io/sh/
vlovich123 · 2020-10-02
You have to dig through the documentation a bit on the website but all the info is there[1]
from sh import mysqldump
from sh import gzip
gzip(mysqldump("example_db", _piped=True), _out="dump.sql.gz")
or if you don't want the magic import thing:
import sh
sh.gzip(sh.mysqldump("example_db", _piped=True), _out="dump.sql.gz")
It's definitely foreign to shell scripting languages since the piping syntax is a bit different & you have to remember to do `_piped=True` since it's not parallel by default. But the default behavior is pipefail & exit on the command failing IIRC so it's more of a choose your poison thing (do you want a subtle perf issue or a subtle bug in your script not handling error states correctly). And I find it easier to read. + if you want to customize anything about gzip or not rely on needing the binary in the path, then you can just switch it to Python-native gzip pretty easily.
That's my favorite feature. Conciseness if I'm just translating a script with progressive complexity options to migrate things that need more complexity or different requirements within the same script without having to rewrite it from scratch.
[1] https://amoffat.github.io/sh/
theamk · 2018-12-13
Note that this recommends "sh" package, which made an _interesting_ decision to run processes in tty by default. This goes against unix conventions that batch processes should not be using tty, and breaks a number of utilities like git and systemctl. This is so bad that even their example from the front page is broken(!):
$ python3
>>> import sh
>>> sh.git.show('HEAD').count('\n')
49
# Now resize your terminal window to be 10 lines tall
>>> sh.git.show('HEAD').count('\n')
9
Yep, it truncated "git show" output to the height of your terminal window. Do you want this in your code?
While you can append special flag for this, it is very easy to forget to do so, and the documentation does not help either. Their FAQ states that they are aware of the issue and won't fix it [0].
So my advice is: stay away from "sh" package, as it makes it very simple to generate unreliable code. Instead, use built-in tools which are pretty nice and just a bit more verbose:
>>> import subprocess
>>> subprocess.check_output('git show HEAD', shell=True).decode().count('\n')
49
[0] https://amoffat.github.io/sh/sections/faq.html#why-is-tty-out-true-the…
groby_b · 2025-01-23
If you mostly want to query and can live without the VFS, dogsheep[1] is your friend. It's a general tool to import lots of different data types into a personal sqlite instance, and dogsheep-photos[2] both extracts image metadata and uploads all the pics to S3 if you'd like.
On my to-try list, there's also supertag[3], a tag-based filesystem that's mounted via FUSE
[1] https://dogsheep.github.io/ [2] https://github.com/dogsheep/dogsheep-photos [3] https://amoffat.github.io/supertag/
Bystroushaak · 2023-06-09
I usually replace shell scripts with python (using sh module: https://amoffat.github.io/sh/ for calling other scripts/programs).
lalopalota · 2023-06-06
> sh relies on various Unix system calls and only works on Unix-like operating systems - Linux, macOS, BSDs etc. Specifically, Windows is not supported.
from: https://amoffat.github.io/sh/
iamjackg · 2023-03-20
100% agree. There are some libraries like https://amoffat.github.io/sh/ that aim to make that easier, but they always have some quirks that, funnily enough, are often the corner cases you were hitting in your complicated Bash script in the first place.
p4bl0 · 2022-07-24
I think the linked page gives a better overview of what this Python lib can do, but if you want to know more:
The repository is here: https://github.com/amoffat/sh
And the full documentation is there: https://amoffat.github.io/sh/index.html
In particular I was wondering if it supports piping, and it does: https://amoffat.github.io/sh/sections/piping.html
But
hoistbypetard · 2022-03-26
> I was hoping someone finally had a library or something to make python good at the things shell does well (mostly, running stuff and piping output around). If only.
I've only kicked the tires on both, but plumbum:
https://plumbum.readthedocs.io/en/latest/
and sh:
https://amoffat.github.io/sh/
both feel pretty good in that regard.
zvr · 2022-02-25
Also related (learned this from HN a couple of weeks ago):
SuperTag https://amoffat.github.io/supertag/
daenz · 2022-01-25
No, but that was a challenge to overcome. See #2 here[0]
0. https://amoffat.github.io/supertag/faq.html#why-are-my-files-in-supert…
ahaferburg · 2021-08-17
https://amoffat.github.io/sh/sections/faq.html
> Will Windows be supported?
> There are no plans to support Windows.
azkae · 2021-08-16
Somewhat related, if you are looking to do scripts in Python you should take a look at `sh`:
import sh
print(sh.ifconfig("eth0"))
https://amoffat.github.io/sh/
kasbah · 2021-05-09
`sh` might be what you are looking for.
https://amoffat.github.io/sh/
andrewshadura · 2021-04-12
> Trying to use Python or Go to whack some external commands together feels very cumbersome to me.
Try https://amoffat.github.io/sh/
from sh.contrib import git
git.reset(hard=True)
esamatti · 2021-03-02
"sh" for python is actually pretty cool
https://amoffat.github.io/sh/
Available as `python3-sh` in Ubuntu.
argonauts12 · 2020-07-09
I've been migrating shell scripts to python and have found the 'sh' library invaluable for pulling in pure CLI commands from the bash script and adding to the python implementation. http://amoffat.github.io/sh/
It's essentially an abstraction layer above subprocess. Quick example - to use ifconfig natively in python:
from sh import ifconfig print(ifconfig("wlan0"))
ThePadawan · 2019-09-19
You might like the python "sh" library [0]. It's not perfect, but it sure does remove the visual noise around subprocess.
[0] https://amoffat.github.io/sh/
int_19h · 2019-04-24
For the kind of thing you've just described, a Python script would need just one dependency to do it all in roughly the same number of lines:
https://amoffat.github.io/sh/
empyrical · 2018-05-20
I think with proxies, you might be able to recreate the magical "sh" library [1] from Python for node.js (wouldn't be surprised if someone already managed this!)
[1] https://amoffat.github.io/sh/
dsnuh · 2018-02-01
I've had good luck with this module. Much nicer than using os.system() imo.
https://amoffat.github.io/sh/
catdog · 2017-08-12
Yes it's entirely possible to create a shell like "program glue" experience in python and somebody already has done it [1][2]. It's only the python standard library which is missing some convenient way to shell out.
[1] http://plumbum.readthedocs.io/en/latest/
[2] http://amoffat.github.io/sh/
jklehm · 2017-06-12
Seems similar to the package sh/pbs. [0]
[0] https://amoffat.github.io/sh/
hultner · 2017-06-11
Very nice!
I've been using somewhat similar sh[1] for the same purpose. It's nice seeing more alternatives.
[1]https://amoffat.github.io/sh/