Migrating from 1.x to 2.x
This document provides an upgrade path from 1.* to 2.*.
sh.cd builtin removed
There is no sh.cd command anymore. It was always a command implemented in
sh, as some systems provide it as a shell builtin, while others have an actual
binary. But neither of them persisted the directory change between other sh
calls, which is why it was implemented in sh.
Workaround
If you were using sh.cd(dir), use the context manager with sh.pushd(dir)
instead. All of the commands in the managed context will have the correct
directory.
Removed execution contexts / default arguments
In 1.* you could spawn a new module from the sh module, one which had
customized defaults for the special keyword arguments. This module could then be
accessed just like sh, and you could even import commands from it.
Unfortunately the magic required to make that work was brittle. Also it was not aligned syntactically with the similar baking concept. We have therefore changed the syntax to align with baking, and also removed the ability to import directly from this new baked execution context.
Workaround
sh2 = sh(_tty_out=False)
sh2.ls()
Becomes:
sh2 = sh.bake(_tty_out=False)
sh2.ls()
And:
sh2 = sh.bake(_tty_out=False)
from sh2 import ls
ls()
Becomes:
sh2 = sh.bake(_tty_out=False)
ls = sh2.ls
ls()
Return value now a true string
In 2.*, the return value of an executed sh command has changed (in most
cases) from a RunningCommand object to a unicode string. This makes using
the output of a command more natural.
Workaround
To continue returning a RunningCommand object, use the _return_cmd=True
special keyword argument. You can achieve this on each file with the following
code at the top of files that use sh:
import sh
sh = sh.bake(_return_cmd=True)
Piping to STDIN
Previously, if the first argument of a sh command was an instance of
RunningCommand, it was automatically fed into the process’s STDIN. This is
no longer the case and you must explicitly use _in=.
from sh import wc, ls
print(wc(ls("/home/<user>", "-l"), "-l"))
Becomes:
from sh import wc, ls
print(wc("-l", _in=ls("/home/<user>", "-l")))
Or:
from sh import wc, ls
print(wc("-l", _in=ls("/home/<user>", "-l", _return_cmd=True)))
Workaround
None.
New processes don’t launch in new session
In 1.*, _new_session defaulted to True. It now defaults to
False. The reason for this is that it makes more sense for launched
processes to default to being in the process group of the Python script, so
that they receive SIGINTs correctly.
Workaround
To preserve the old behavior:
import sh
sh = sh.bake(_new_session=True)