Python Session 05: Subprocess

Shell integration. This session covers running external commands, capturing output, and environment handling.

Pre-Session State

  • Understand functions and classes

  • Can work with files

  • Know string processing

Lesson 1: Basic subprocess.run

Concept: Use subprocess.run() to execute commands.

Exercise 1.1: Simple command

import subprocess

result = subprocess.run(['ls', '-la', '/tmp'], capture_output=True, text=True)
print(result.stdout)
print(f"Return code: {result.returncode}")

Exercise 1.2: Check return code

import subprocess

result = subprocess.run(['ping', '-c', '1', 'localhost'], capture_output=True, text=True)

if result.returncode == 0:
    print("Host is reachable")
else:
    print("Host unreachable")
    print(result.stderr)

Exercise 1.3: Raise on error

import subprocess

try:
    result = subprocess.run(['ls', '/nonexistent'], capture_output=True, text=True, check=True)
except subprocess.CalledProcessError as e:
    print(f"Command failed: {e}")
    print(f"stderr: {e.stderr}")

Lesson 2: Shell Commands

Concept: Use shell=True for shell features (pipes, etc).

Exercise 2.1: Shell pipeline

import subprocess

# Note: shell=True has security implications - don't use with untrusted input
result = subprocess.run('ps aux | grep python | head -5', shell=True, capture_output=True, text=True)
print(result.stdout)

Exercise 2.2: Better: avoid shell=True

import subprocess

# Safer: pipe between processes
ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
grep = subprocess.Popen(['grep', 'python'], stdin=ps.stdout, stdout=subprocess.PIPE)
ps.stdout.close()
output = grep.communicate()[0]
print(output.decode())

Lesson 3: Environment Variables

Concept: Access and modify environment for subprocesses.

Exercise 3.1: Read environment

import os

print(os.environ.get('HOME'))
print(os.environ.get('VAULT_ADDR', 'not set'))

# All environment
for key, value in os.environ.items():
    if 'PATH' in key:
        print(f"{key}: {value[:50]}...")

Exercise 3.2: Set environment for subprocess

import subprocess
import os

my_env = os.environ.copy()
my_env['MY_VAR'] = 'my_value'

result = subprocess.run(['printenv', 'MY_VAR'], capture_output=True, text=True, env=my_env)
print(result.stdout)  # my_value

Exercise 3.3: Expand variables

import os

path = os.path.expandvars('$HOME/.ssh/config')
print(path)  # /home/user/.ssh/config

user_home = os.path.expanduser('~')
print(user_home)  # /home/user

Lesson 4: Practical Patterns

Concept: Real-world subprocess patterns.

Exercise 4.1: Run and parse JSON output

import subprocess
import json

result = subprocess.run(['kubectl', 'get', 'pods', '-o', 'json'], capture_output=True, text=True)

if result.returncode == 0:
    data = json.loads(result.stdout)
    for pod in data.get('items', []):
        print(pod['metadata']['name'])

Exercise 4.2: Timeout handling

import subprocess

try:
    result = subprocess.run(['sleep', '10'], timeout=2, capture_output=True)
except subprocess.TimeoutExpired:
    print("Command timed out")

Exercise 4.3: Working directory

import subprocess

result = subprocess.run(['pwd'], capture_output=True, text=True, cwd='/tmp')
print(result.stdout.strip())  # /tmp

result = subprocess.run(['git', 'status'], capture_output=True, text=True,
                       cwd='/home/user/project')

Exercise 4.4: Build command dynamically

import subprocess
import shlex

host = "10.50.1.110"
cmd = ['ssh', '-o', 'ConnectTimeout=5', host, 'uptime']

result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)

# If you have a string command, use shlex.split
cmd_str = "ls -la /tmp"
cmd_list = shlex.split(cmd_str)
print(cmd_list)  # ['ls', '-la', '/tmp']

Summary: What You Learned

Concept Syntax Example

Run command

subprocess.run(cmd)

subprocess.run(['ls', '-la'])

Capture output

capture_output=True

result.stdout, result.stderr

Text mode

text=True

Returns str instead of bytes

Check error

check=True

Raises CalledProcessError

Timeout

timeout=N

Raises TimeoutExpired

Working dir

cwd='/path'

Run in specific directory

Environment

env=dict

Custom environment

Split command

shlex.split(str)

Safe string to list

Exercises to Complete

  1. [ ] Write function to ping host and return True/False

  2. [ ] Run ip addr and parse output for IP addresses

  3. [ ] Execute command with timeout and retry logic

  4. [ ] Build a wrapper for netapi ise mnt sessions

Next Session

Session 06: Infrastructure - HTTP, argparse, config, logging.

Session Log

Timestamp Notes

Start

<Record when you started>

End

<Record when you finished>