← Back to blog

How to Run Bash in Jupyter Notebook

· 5 min read · Stew Team
jupyter notebookbashdevops

Jupyter Notebook is built for Python, but you can run bash commands too. Here’s how to run bash in Jupyter Notebook using every available method.

Method 1: The ! Shell Escape

The simplest way to run bash in Jupyter Notebook is the shell escape prefix:

!ls -la
!kubectl get pods -n production
!docker ps

Any line starting with ! runs in your system shell.

Capturing Output

Store command output in a Python variable:

pods = !kubectl get pods -n production -o name
print(pods)
# ['pod/api-7d4f8b6c9-x2k4j', 'pod/api-7d4f8b6c9-k8m2n']

Using Python Variables

Pass Python variables to shell commands:

namespace = "production"
!kubectl get pods -n {namespace}

Limitations

  • Each ! command runs in a new shell
  • Environment variables don’t persist between commands
  • Can’t run interactive commands

Method 2: The %%bash Cell Magic

For multi-line bash scripts, use the %%bash cell magic:

%%bash
echo "Starting deployment..."
kubectl get pods -n production
kubectl rollout restart deployment/api -n production
echo "Done!"

With Error Handling

%%bash
set -e
kubectl get pods -n production
kubectl rollout restart deployment/api -n production
kubectl rollout status deployment/api -n production

Capturing Output to Variables

%%bash --out output --err error
kubectl get pods -n production
print(output)
print(error)

Limitations

  • Still runs in a subprocess
  • No interactivity
  • The entire cell runs at once—no step-by-step execution

Method 3: The %%script Magic

For specific shells or interpreters:

%%script bash
echo "Running in bash"
%%script zsh
echo "Running in zsh"
%%script sh
echo "Running in sh"

Method 4: Install a Bash Kernel

For notebooks that are primarily bash, install a dedicated kernel:

pip install bash_kernel
python -m bash_kernel.install

Now create notebooks with the Bash kernel. Every cell runs as bash:

# Cell 1
kubectl get nodes

# Cell 2
kubectl get pods -n production

# Cell 3
kubectl describe pod api-7d4f8b6c9-x2k4j -n production

Advantages

  • Native bash experience
  • Environment variables persist between cells
  • Better syntax highlighting

Disadvantages

  • Can’t mix Python and bash in the same notebook
  • Still requires Jupyter infrastructure
  • Not as widely supported

Method 5: Using subprocess

For more control, use Python’s subprocess module:

import subprocess

result = subprocess.run(
    ["kubectl", "get", "pods", "-n", "production"],
    capture_output=True,
    text=True
)
print(result.stdout)
if result.returncode != 0:
    print(f"Error: {result.stderr}")

With Streaming Output

import subprocess

process = subprocess.Popen(
    ["kubectl", "logs", "-f", "api-7d4f8b6c9-x2k4j"],
    stdout=subprocess.PIPE,
    text=True
)

for line in process.stdout:
    print(line, end="")

Common Issues When Running Bash in Jupyter Notebook

PATH Not Found

Jupyter may not have the same PATH as your terminal:

import os
os.environ["PATH"] += ":/usr/local/bin:/opt/homebrew/bin"

Or specify full paths:

!/usr/local/bin/kubectl get pods

Environment Variables

Set environment variables for the session:

%env KUBECONFIG=/path/to/kubeconfig

Or in Python:

import os
os.environ["KUBECONFIG"] = "/path/to/kubeconfig"

SSH Commands

SSH can be tricky in Jupyter:

!ssh -o BatchMode=yes user@server "hostname"

Ensure SSH keys are set up for non-interactive authentication.

Interactive Commands

Interactive commands don’t work well:

# This will hang or fail
!vim file.txt  # ❌
!top           # ❌
!ssh user@host # ❌ (interactive)

When Jupyter Works for Bash

Jupyter is reasonable for:

  • Data analysis pipelines with occasional shell commands
  • Exploratory work where you’re mixing Python and bash
  • Documentation that shows commands and their output

When Jupyter Falls Short

Jupyter isn’t ideal for:

Operations Runbooks

Running bash in Jupyter Notebook for ops work has problems:

  • Heavy infrastructure: Jupyter Server, kernels, browser
  • No SSH support: Can’t easily run commands on remote servers
  • Poor portability: .ipynb files don’t work in standard editors
  • Version control noise: Notebook JSON creates messy diffs

Incident Response

During incidents, you don’t want to:

  • Start a Jupyter server
  • Wait for the kernel to connect
  • Navigate cells with a mouse

Team Sharing

Jupyter notebooks require everyone to have Jupyter installed. Markdown files work everywhere.

A Better Way to Run Bash in Notebooks

If you’re learning how to run bash in Jupyter Notebook for DevOps or ops work, consider purpose-built alternatives.

What you actually want:

  • Markdown files (not JSON notebooks)
  • Step-by-step execution
  • SSH support for remote servers
  • Works in terminal or browser
  • Git-friendly

That’s what Stew provides. Write bash commands in Markdown:

# Restart API

Check current status:

​```bash
kubectl get pods -n production -l app=api
​```

Restart deployment:

​```bash
kubectl rollout restart deployment/api -n production
​```

Execute each block independently, see output inline, run locally or over SSH.

Summary

Here’s how to run bash in Jupyter Notebook:

MethodBest For
!commandQuick one-liners
%%bashMulti-line scripts
Bash kernelPure bash notebooks
subprocessProgrammatic control

For data science mixed with shell commands, Jupyter works. For operations and infrastructure, there are better tools.

Join the waitlist for Stew—bash notebooks built for ops.