Scott Stevenson

Viewing Jupyter notebooks at the command line

The Jupyter notebook is a literate programming environment that has become ubiquitous in machine learning. While the standard tools for interacting with notebooks are web applications, it’s often useful to be able to view notebooks at the command line. This is convenient when you’re logged into a training workstation via SSH, and the process of configuring SSH to forward a port, starting a Jupyter server, and navigating to it in a web browser is a chore to view a notebook for a few seconds.

Viewing other literate programming formats such as R Markdown and Pweave at the command line is trivial: these use lightweight markup languages that don’t need special rendering to be legible. As such, it’s enough to just cat the file contents to the terminal.

This isn’t the case for Jupyter notebooks, though. A notebook is a structured JSON document conforming to a schema. Notebooks can contain images and other binary data, which, when viewed with a pager, will print unintelligible Base64 encoded data to your terminal. Characters such as " are backslash-escaped, making copying code from the output impossible.

Instead of printing the notebook file directly to the terminal, let’s convert it to another format first. nbconvert is a program to convert notebooks to rich formats, including HTML and PDF, as well as plain text such as Markdown. By design, Markdown syntax is unobtrusive and readable in plain text without rendering, so it’s a good choice of output format.

As an example, we’ll use a notebook that contains both prose and code cells taken from the JAX documentation.

A Jupyter notebook rendered in JupyterLab

You can use jupyter nbconvert to convert the notebook to Markdown, printing the output to standard output, with:

jupyter nbconvert --stdout --to markdown thinking_in_jax.ipynb

nbconvert writes a header [NbConvertApp] Converting notebook thinking_in_jax.ipynb to markdown to standard error and the notebook body to standard output, so filter out the header by redirecting standard error:

jupyter nbconvert --stdout --to markdown thinking_in_jax.ipynb 2>/dev/null

This redirection syntax is for Bourne-like shells such as Bash. If you’re using an alternative such as fish, change as appropriate.

This is already more readable than the raw JSON document, but we can improve the readability of the code cells by applying syntax highlighting. We’ll pipe the output of nbconvert to pygmentize, a command line interface to the Pygments syntax highlighting library. Pygments is a dependency of nbconvert, so if you’ve followed this post so far, you’ve already installed it.

As we’re piping text to pygmentize on standard input, there’s no filename from which to determine the language of the input, so we need to specify it using the -l flag:

jupyter nbconvert --stdout --to markdown thinking_in_jax.ipynb 2>/dev/null |
  pygmentize -l md

Let’s pipe the output of pygmentize to a pager like less to scroll through and search within the notebook:

jupyter nbconvert --stdout --to markdown thinking_in_jax.ipynb 2>/dev/null |
  pygmentize -l md | less -R

The -R flag instructs less to output ANSI escape sequences in raw form to colour the output. If you run this command, you’ll get a legible rendering of the notebook with syntax highlighting. Thanks to less, you can scroll up and down through the notebook, and search within it by pressing / and typing a query.

Output of nbless in a terminal emulator

This is a longer command than is convenient to type for each use, so let’s create a shell script to encapsulate it, and also take the opportunity to add some input validation:

#!/usr/bin/env bash

set -euo pipefail

readonly EX_USAGE=64
readonly EX_NOINPUT=66
readonly EX_UNAVAILABLE=69

usage() {
  echo "usage: $(basename "$0") [-h] NOTEBOOK"
  echo
  echo "Convert a Jupyter notebook to Markdown and view with less"
}

if [[ $# -ne 1 ]]; then
  usage
  exit $EX_USAGE
fi

if [[ "$1" = -h || "$1" = --help ]]; then
  usage
  exit
fi

if [[ ! -f "$1" ]]; then
  echo "$(basename "$0"): $1: No such file"
  exit $EX_NOINPUT
fi

if ! command -v jupyter >/dev/null; then
  echo >&2 "$(basename "$0"): command not found: jupyter"
  exit $EX_UNAVAILABLE
fi

jupyter nbconvert --stdout --to markdown "$1" 2>/dev/null |
  pygmentize -l md | less -R

Save this as an executable script on your shell’s command search path, for example, as nbless, and the next time you’re at the command line and want to view a notebook, run nbless notebook.ipynb – no port forwarding, Jupyter server, or web browser required!