Sh.py
amoffat.github.com
amoffat.github.com
http://plumbum.readthedocs.org/en/latest/index.html
Here's the explanation on the differences:
"The project has been inspired by PBS of Andrew Moffat, and has borrowed some of his ideas (namely treating programs like functions and the nice trick for importing commands). However, I felt there was too much magic going on in PBS, and that the syntax wasn’t what I had in mind when I came to write shell-like programs. I contacted Andrew about these issues, but he wanted to keep PBS this way. Other than that, the two libraries go in different directions, where Plumbum attempts to provide a more wholesome approach."
Written in 1994, by Larry himself!
http://amoffat.github.com/sh/index.html#interactive-callback...
Lets you replace `expect` with Python code pretty darn easily.
On the other hand, if I have an application that needs to communicate with a subprocess as a small piece of the whole, I'll use other methods that are less "magical". It's not that I'm inherently against magic, but rather that, in that use case, I generally want very explicit control over what is happening.
from sh import git
there's no module 'sh' invoked in the normal sense. Instead, the library generates a wrapper for the shell command 'git' on the fly. While that kind of monkey patching may be neat, it's also a bit brittle and a potential security issue.It is also not "monkeypatching", which ought to be reserved for things that involve reaching into an existing class and modifying things. This on-demand loading, which doesn't have anywhere near the same evil factor, but is rather more like dynamic programming languages working-as-designed.
You may find this distasteful. I do, actually, though I'm not 100% sure why. But it's not because it's some sort of abuse of Python. Python is very nearly designed to do this, and the last little bit that it isn't designed for isn't that big a deal, especially compared to something like the "import python modules through zipfiles" functionality, which now ships with the core.
import os
os.system('insert local exploit here')
It's true that it is another place that you can get a python script to execute code outside of its environment, but you get a ton of those for free with the stdlib.This is something that python specifically has language level support for, I wouldn't say it's a hack just because its using a feature that isn't taught in Python 101.
import sh
git = sh.Command("/usr/bin/git")
the Command object takes a full path, but you can use it together with sh's "which": import sh
git = sh.Command(sh.which("git")) $ pip install sh
or goto the github page https://github.com/amoffat/sh[1]: http://www.clemesha.org/blog/modern-python-hacker-tools-virt...
For those of you who are just learning, PIP will automatically download, install, and then compile any python modules you point it at. Just make sure you have the module's recommended compilers installed first.
This version introduces many positive changes: specially 'Iterating over output' that I have been waiting for a long time.
Andrew wants to increase his support for MacOS and would like to have test results from "python setup.py test" (to run the whole test suite). One identified bug is: http://bugs.python.org/issue15898
I would love to see more people use this to simplify their work!
If anyone is interested in looking into the scripts I wrote to see what's possible, let me know.
Not meant as a snide remark; genuinely curious.
Although its functions are a subset of sh for python. It has many synatactic sugars, makes full use of ruby Enumerable, and does lazy-execute.
Due to the cross-platform needs of Mozilla's PDF.js build scripts, we've been writing a Node.js lib on top of Node's APIs that enables you to write shell-like scripts that run seamlessly on multiple platforms:
Like Sh.py, you can (if you must) also run external commands, either synchronously or asynchronously.
http://www.github.com/gameclosure/jash
It's probably not ready for prime time - past it's initial use cases it hasn't been tested much. Things like sh.py and jash are a really neat solution for some problems.
I still believe that wrapping shell commands with functions is the way to go. Functions can intelligently check their arguments and prevent propagation of dangerous (or otherwise obviously incorrect) arguments.
This way you then have to parse the output of ifconfig, say.
eg I have been doing this for Lua [1] you can do
> i = nl.interfaces()
> print(i.lo)
lo Link encap:Local Loopback inet addr: 127.0.0.1/8 inet6 addr: ::1/128 UP LOOPBACK RUNNING LOWER_UP MTU: 16436 RX packets:261454 errors:0 dropped:0 TX packets:261454 errors:0 dropped:0
> print(i.eth0.macaddr)
f0:da:f0:38:36:39
The functionality is now reasonably comprehensive, so you can rename interfaces, add addresses, although it is still a work in progress, as there is a fair amount of work involved as there is a lot of shell to implement, but it can be incrementally useful.
Deleted comment
Cute, but definitely on the list of things I'd remove on sight if encountered in a commercial project.
And what's the best way to quickly look and see which versions a package is compatible with?
# unless __name__ == "__main__"
self = sys.modules[__name__]
# SelfWrapper has a custom __getattr__
sys.modules[__name__] = SelfWrapper(self)
which seems somewhat unpythonesque (aren't import hooks supposed to be used for this?) but it's cool and I hadn't seen it before.A common example of this that I use quite often is "clear" or "cls". It makes the determination what OS it's using, then issues the appropriate command to clear the terminal window.