Running Scripts from IPython¶
IPython has a %%script
cell magic, which lets you run a cell in
a subprocess of any interpreter on your system, such as: bash, ruby, perl, zsh, R, etc.
It can even be a script of your own, which expects input on stdin.
import sys
Basic usage¶
To use it, simply pass a path or shell command to the program you want to run on the %%script
line,
and the rest of the cell will be run by that script, and stdout/err from the subprocess are captured and displayed.
%%script python2
import sys
print 'hello from Python %s' % sys.version
%%script python3
import sys
print('hello from Python: %s' % sys.version)
IPython also creates aliases for a few common interpreters, such as bash, ruby, perl, etc.
These are all equivalent to %%script <name>
%%ruby
puts "Hello from Ruby #{RUBY_VERSION}"
%%bash
echo "hello from $BASH"
Capturing output¶
You can also capture stdout/err from these subprocesses into Python variables, instead of letting them go directly to stdout/err
%%bash
echo "hi, stdout"
echo "hello, stderr" >&2
%%bash --out output --err error
echo "hi, stdout"
echo "hello, stderr" >&2
print(error)
print(output)
Background Scripts¶
These scripts can be run in the background, by adding the --bg
flag.
When you do this, output is discarded unless you use the --out/err
flags to store output as above.
%%ruby --bg --out ruby_lines
for n in 1...10
sleep 1
puts "line #{n}"
STDOUT.flush
end
When you do store output of a background thread, these are the stdout/err pipes, rather than the text of the output.
ruby_lines
print(ruby_lines.read())
Arguments to subcommand¶
You can pass arguments the subcommand as well, such as this example instructing Python to use integer division from Python 3:
%%script python2 -Qnew
print 1/3
You can really specify any program for %%script
,
for instance here is a 'program' that echos the lines of stdin, with delays between each line.
%%script --bg --out bashout bash -c "while read line; do echo $line; sleep 1; done"
line 1
line 2
line 3
line 4
line 5
Remember, since the output of a background script is just the stdout pipe, you can read it as lines become available:
import time
tic = time.time()
line = True
while True:
line = bashout.readline()
if not line:
break
sys.stdout.write("%.1fs: %s" %(time.time()-tic, line))
sys.stdout.flush()
Configuring the default ScriptMagics¶
The list of aliased script magics is configurable.
The default is to pick from a few common interpreters, and use them if found, but you can specify your own in ipython_config.py:
c.ScriptMagics.scripts = ['R', 'pypy', 'myprogram']
And if any of these programs do not appear on your default PATH, then you would also need to specify their location with:
c.ScriptMagics.script_paths = {'myprogram': '/opt/path/to/myprogram'}