Step 51. The Standard Library — The Toolbox Already Inside Python

Step 51. The Standard Library — The Toolbox Already Inside Python

Level 1 — Programming and the Computer’s Insides | Difficulty ★★☆☆☆ | Estimated time: 3 hours

Prerequisites: Steps 41–50 complete. You know basic Python syntax and how to import modules. You must be able to create a Python script (.py) and run it in the terminal with python filename.py.

  • What you need: a PC with Python installed, a text editor, a terminal (PowerShell or Git Bash).
  • Caution: today’s practice is 100% safe. Everything you do is "looking things up" and "capturing output." The tool you build at the end does execute operating system commands, but the commands used in the examples, like ipconfig, are view-only.

The moment you installed Python, hundreds of tools were installed on your computer along with it. These built-in tools, ready to use with a single import line and no installation, are called the standard library. The random, re, and datetime you’ve used so far were all part of it.

The three tools you’ll meet today have different personalities. os, sys, and subprocess are "phone lines between Python and the operating system." os is the phone for looking at files and folders, sys is the phone for looking at information about the script itself, and subprocess is the phone for ordering the operating system to run commands. Once these phone lines open, Python leaves the text playground and starts commanding the whole computer. Half of what security tools do happens right on top of these phone lines.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Explain what the standard library is, and find and import the module you need
  • Query the current location, file lists, and file information with the os module
  • Receive and process command-line arguments (values typed after the command) with sys.argv
  • Run operating system commands from inside Python and capture their output with subprocess
  • Build a small tool yourself that runs whatever command it’s handed as an argument

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/environment Python 3.12, terminal (PowerShell). All standard library — nothing new to install
Today’s syntax os.getcwd() / os.listdir() / os.path.join() / os.environ, sys.argv / sys.exit(), subprocess.run(), .decode("cp949")
Concepts needed The standard library, command-line arguments, environment variables (PATH), the return code (returncode)

2-1. The Standard Library — The Built-In Toolbox

The collection of modules included in the official Python distribution is the standard library. Math calculations, dates, files, network basics — more than half of the "can Python do this?" jobs are already in here. The full list is in the official documentation (docs.python.org/3/library). Today we pick out the three that connect to the operating system.

2-2. os — The Counter to the Operating System

The operating system is the computer’s general manager, and the os module is the counter where you ask that manager questions and give orders. You ask questions like "which folder am I in now?" (getcwd), "what’s in this folder?" (listdir), and "join these paths the operating system’s way" (path.join).

2-3. sys.argv — How to Talk to a Script

sys is the module about the running Python itself. Today’s star is sys.argv, the list holding the command-line arguments. These are the extra values you type after the script name, separated by spaces, like python mytool.py hello. Slot 0 always holds the script’s own name, and from slot 1 onward come the arguments we typed.

2-4. subprocess — The Phone That Gives Orders

This module runs the commands you used to type in the terminal (ipconfig, dir, and the like) from inside Python code, and even captures their output. Security tools use this approach when they call external programs. The execution result comes with a return code (returncode), and 0 is the promise meaning success.

2-5. Environment Variables — The Operating System’s Notepad

An environment variable is a settings memo the operating system posts publicly for all programs. The most famous is PATH — the list of folders where it looks for the executable when you type a command. The reason python.exe runs when you type python in the terminal is that the Python folder is in this list (the very thing you touched in Step 41).


3. Follow Along

3-1. os — Where Am I Right Now?

In your working folder (the security-study folder you’ll practice in), create os_lab.py:

import os

print("Current folder:", os.getcwd())
print("File list:", os.listdir())
Current folder: C:\Users\dlqht\Documents\...\tmp_test
File list: ['os_lab.py', 's51_1_os.py', 's51_2_greet.py', ...]

(Measured 2026-09-09. The folder path and file list will differ from yours.)

How to read the output: getcwd() is short for "get current working directory." The script interprets relative paths relative to this folder. listdir() gives you the names inside that folder as a list.

Why: "where is my program standing right now, and what is it looking at" is the starting point of every file operation.

3-2. Joining Paths — os.path.join

import os

print(os.path.join("reports", "result.txt"))
print(os.path.join("a", "b", "c.txt"))
reports\result.txt
a\b\c.txt

(Measured 2026-09-09, Windows. On Mac and Linux they’re joined with /.)

How to read the output: joining paths with string addition breaks because the separator differs per operating system (\ vs /). os.path.join picks the separator that fits the current operating system for you. It’s the way to make the same code work on any operating system.

Predict: what will os.path.exists("os_lab.py") give you? Predict, then run it.

3-3. Peeking at Environment Variables

import os

print("User:", os.environ.get("USERNAME"))
print("Start of PATH:", os.environ.get("PATH")[:60], "...")
User: dlqht
Start of PATH: C:\Users\dlqht\AppData\Roaming\kimi-desktop\daimon-sha ...

(Measured 2026-09-09. Your username and PATH will appear.)

How to read the output: os.environ behaves like a dictionary holding all environment variables, and .get("NAME") pulls out one at a time. PATH is a long list of folders separated by semicolons. When subprocess looks for a command later, it searches exactly this list.

3-4. sys.argv — Talking to a Script

Create greet.py:

import sys

print("All arguments:", sys.argv)
print("Script name:", sys.argv[0])
if len(sys.argv) > 1:
    print("First argument:", sys.argv[1])

Run it in the terminal with arguments attached:

python greet.py hello security
All arguments: ['greet.py', 'hello', 'security']
Script name: greet.py
First argument: hello

Run it without arguments:

python greet.py
All arguments: ['greet.py']
Script name: greet.py

(Measured 2026-09-09.)

How to read the output: slot 0 is always the script name; from slot 1 onward are the arguments we typed. The if len(sys.argv) > 1: check is the convention that prevents "if no argument comes in, slot 1 itself doesn’t exist and it dies" — note that the last line didn’t appear in the second measurement, run without arguments.

Why: tools like nmap -p 80 target all work on this structure. This is the first step of our tool receiving arguments the same way.

3-5. subprocess — Sending the OS on an Errand

Create runner.py:

import subprocess

result = subprocess.run(
    ["ipconfig"],
    capture_output=True,
    text=False
)
output = result.stdout.decode("cp949", errors="replace")
print(output[:200])
print("...")
print("Return code:", result.returncode)
Windows IP 구성


알 수 없는 어댑터 Tailscale:

   연결별 DNS 접미사. . . . : tail88dfb9.ts.net
...
Return code: 0

(Measured 2026-09-09, Korean Windows. Network configuration differs per computer.)

How to read the output: you hand the command to subprocess.run() as a list to run it. capture_output=True means "don’t splash the output on the screen — give it to me," and that result lands in result.stdout as bytes. Windows command output is written in the cp949 code page for Korean, so you decode it with Step 50’s knowledge. Broken characters get replaced by errors="replace". Return code 0 is "command succeeded."

Why: this is the moment Python can directly run the network commands (Steps 27~34) and analyze their results. The beginning of automation.

3-6. A Command-Running Script — Putting It Together

Create cmdtool.py:

import sys
import subprocess

if len(sys.argv) < 2:
    print("Usage: python cmdtool.py <command> [options...]")
    sys.exit(1)

result = subprocess.run(sys.argv[1:], capture_output=True)
print(result.stdout.decode("cp949", errors="replace"))
if result.returncode != 0:
    print("The command failed. Code:", result.returncode)

Run it:

python cmdtool.py ipconfig /all
Windows IP 구성

   호스트 이름 . . . . . . . : XI3492
   주 DNS 접미사 . . . . . . :
   노드 유형 . . . . . . . . : 혼성
   IP 라우팅 사용. . . . . . : 아니요
   ...

(Measured 2026-09-09. The host name and such differ per computer.)

How to read the output: sys.argv[1:] slices from slot 1 to the end — the whole command we typed, as a list. Now this script has become a small shell that takes any command as arguments and runs it. sys.exit(1) means "end here, but with a non-zero code" — the convention for telling the operating system it ended in failure.

3-7. os.path — Asking About a File

Beyond joining paths, os.path answers questions about files. Create fileinfo.py and run it in the same folder:

import os

name = "fileinfo.py"
print("Exists?", os.path.exists(name))
print("Size (bytes):", os.path.getsize(name))
print("Extension:", os.path.splitext(name))
print("Missing file:", os.path.exists("no_such_file.xyz"))
Exists? True
Size (bytes): 486
Extension: ('fileinfo', '.py')
Missing file: False

(Measured 2026-09-09. The size changes every time you save the file.)

How to read the output: exists asks whether it’s there, getsize how big it is, and splitext splits the name and extension into two. splitext‘s result is a tuple (an ordered bundle), with [0] the name and [1] the extension.

Watch out: these files are looked up relative to the folder where you ran the script. In our measurement, we too ran it from a different folder and hit FileNotFoundError: [WinError 2] The system cannot find the file specified. The reference point of a relative path is not "where the file is" but "where you typed the command."

Why: "check whether a file exists, create it if it doesn’t, classify it by extension" — the three most common moves of an automation script are all in here.


4. Missions & Exercises

Mission — Build a System Inspection Tool

Create syscheck.py and implement the following:

  1. It picks a feature by argument and runs it:
    • python syscheck.py files → prints the current folder’s file list and total count
    • python syscheck.py net → prints the result of running ipconfig
    • python syscheck.py env → prints the username and PATH
    • No argument → prints the usage guide above
  2. In the files feature, also count and show the counts by extension (use a dictionary + splitext)
  3. Also save the results to inspection_result.txt (Step 45 review)
  4. Split each feature into a function, and add exception handling so the program doesn’t die on failure (Step 46 review)

Exercises

Q1. What’s the difference between the standard library and external packages (which you’ll learn in Step 53)? How does the preparation needed before using each differ?

Q2. What’s in slot 0 of sys.argv, and why must you check the length before reading sys.argv[1]?

Q3. When handing a command to subprocess, why split it into a list like ["ipconfig", "/all"]? What happens if you put it in one slot like ["ipconfig /all"]?

Q4. You captured a Windows command’s output, but the Korean looks broken. State the cause and the fix in code.


5. Model Answers & Completion Criteria

Mission Model Answer

import sys
import os
import subprocess

def show_files(lines):
    names = os.listdir()
    lines.append(f"{len(names)} files:")
    ext_count = {}
    for n in names:
        lines.append("  " + n)
        ext = os.path.splitext(n)[1] or "(no extension)"
        ext_count[ext] = ext_count.get(ext, 0) + 1
    lines.append("--- by extension ---")
    for ext, c in ext_count.items():
        lines.append(f"  {ext}: {c}")

def show_net(lines):
    try:
        r = subprocess.run(["ipconfig"], capture_output=True)
        lines.append(r.stdout.decode("cp949", errors="replace"))
    except FileNotFoundError:
        lines.append("Could not find ipconfig.")

def show_env(lines):
    lines.append("User: " + str(os.environ.get("USERNAME")))
    lines.append("PATH: " + str(os.environ.get("PATH")))

lines = ["=== System Inspection Result ==="]
if len(sys.argv) < 2:
    print("Usage: python syscheck.py [files|net|env]")
    sys.exit(1)

if sys.argv[1] == "files":
    show_files(lines)
elif sys.argv[1] == "net":
    show_net(lines)
elif sys.argv[1] == "env":
    show_env(lines)
else:
    lines.append("Unknown feature: " + sys.argv[1])

print("\n".join(lines))
with open("inspection_result.txt", "w", encoding="utf-8") as f:
    f.write("\n".join(lines))

How to verify: ① Do the three arguments (files, net, env) each work? ② Does running with no argument print the usage and end quietly? ③ After running, does inspection_result.txt exist with the same content as the screen output? ④ ext_count.get(ext, 0) is the dictionary tallying convention meaning "treat it as 0 if absent" (Step 42 review). The point is using the same lines list for both screen output and file saving — you build the content once and send it to two places.

Exercise Solutions

Q1 solution. The standard library is the built-in modules that come with the Python installation — you can use them right away with just import. External packages must be installed separately with pip. The difference in preparation is summed up in one line: "does it require installation?"

Q2 solution. Slot 0 holds the script’s own name. If you run without arguments, the list has only slot 0, so sys.argv[1] points to a slot that doesn’t exist, and you get the IndexError: list index out of range we saw in measurement. That’s why the convention is to check if len(sys.argv) < 2: first, and if missing, show the usage and end.

Q3 solution. Because the convention is that one list slot is "the program name" and the following slots are "the options." If you put it in one slot like ["ipconfig /all"], Python looks for a program named "ipconfig /all" — no such program exists, so it fails (measured 2026-09-09: FileNotFoundError: [WinError 2] The system cannot find the file specified). The list style is also a safe habit that reduces the risk of command injection (slipping in malicious commands).

Q4 solution. Because Windows command output is written in the cp949 code page, not utf-8. Decode with result.stdout.decode("cp949", errors="replace"). "If the output is broken, suspect the code page" is the common sense you learned in Step 50.

Completion Criteria Checklist

  • [ ] I can explain what the standard library is
  • [ ] I can investigate the current folder with os.getcwd and os.listdir
  • [ ] I can use os.path.join/exists/getsize/splitext
  • [ ] I can receive arguments with sys.argv and process them together with a length check
  • [ ] I can run a command with subprocess.run and decode its output with cp949
  • [ ] I can explain that relative paths are based on "the folder you ran from"
  • [ ] Mission: I completed syscheck.py and even saved inspection_result.txt

6. Common Pitfalls & Fixes

Wall 1. IndexError: list index out of range

Symptom: it dies while reading sys.argv[1] (measured 2026-09-09):

IndexError: list index out of range

Cause: you ran it without arguments, so slot 1 doesn’t exist.
Fix: check if len(sys.argv) < 2: first, and if missing, show the usage and end with sys.exit(1). A friendly tool explains its usage first.

Wall 2. Korean comes out broken

Symptom: Korean appears as broken characters in subprocess output.
Cause: Windows command output uses the cp949 code page, but you printed it as-is or decoded it as utf-8.
Fix: .decode("cp949", errors="replace"). In the measured environment (Korean Windows) too, Korean like "알 수 없는 어댑터" read correctly only after decoding.

Wall 3. FileNotFoundError — a command that works in the terminal doesn’t work

Symptom (measured 2026-09-09, when running the ver command):

FileNotFoundError: [WinError 2] The system cannot find the file specified

Cause: there are two cases. ① You typoed the command name, or that program isn’t in PATH. ② It’s a built-in command of cmd.exe like ver — built-in commands have no standalone executable file, so subprocess can’t find them.
Fix: first check whether that command exists as an executable file (ipconfig exists as a file; ver and dir are built-in features of cmd). If you absolutely need a built-in command, run it through cmd, like ["cmd", "/c", "ver"].

Wall 4. Putting the whole command in one slot

Symptom: subprocess.run(["ipconfig", "/all"]) works, but ["ipconfig /all"] fails (measured 2026-09-09, both verified).
Cause: one list slot is entirely "the program name." There’s no program named "ipconfig /all".
Fix: split the command and options into list slots. For reference, on Windows a single string like subprocess.run("ipconfig /all") happens to work sometimes (verified by measurement) — but the moment a space slips into a path it tangles, so make the list style, safe on any operating system, your habit.

Wall 5. The file is clearly there, but it says it isn’t

Symptom: os.path.exists("mylog.txt") is False, or getsize raises FileNotFoundError.
Cause: the reference point of a relative path is not the folder containing the file but the folder where you ran the command (the value of getcwd). Run from a different folder and it can’t find it (reproduced in the 2026-09-09 measurement).
Fix: make a habit of checking where you’re standing with print(os.getcwd()) before running. This one line catches 90% of path problems.


7. Summary

Today’s Concepts

Concept One-line description
Standard library The module collection built into Python — just import
Command-line arguments The values after python tool.py value, received via sys.argv
Environment variables Settings memos the OS posts publicly (PATH, etc.)
Return code A command’s report card — 0 means success
cp949 The character code page of Korean Windows command output

Today’s Syntax

Syntax What it does
os.getcwd() Current working folder
os.listdir() List of names inside a folder
os.path.join(a, b) Join paths the OS’s way
os.path.exists(p) / getsize(p) / splitext(p) Existence / size / split extension
os.environ.get("PATH") Read an environment variable
sys.argv Command-line argument list (slot 0 is the script name)
sys.exit(1) Exit with a failure code
subprocess.run([...], capture_output=True) Run a command + capture output
.decode("cp949", errors="replace") Decode Windows command output

The Instinct That Matters More Than Commands

Today Python crossed the wall of the text playground. Asking the operating system (os), ordering it (subprocess), and receiving the results — now your code can move the whole computer. Delegating repetitive errands to code: that is the scripting mindset.

Remember two more things. First, before ordering anything with subprocess, make a habit of writing down three things: (a) does this command work when typed directly in the terminal, (b) what will I do with the output I capture, (c) what will I do if it fails (returncode ≠ 0). With this design memo, the code comes out on its own. Second, "a program that runs any command" is as powerful as it is a target for attack. Handed a strange argument, it becomes a channel for command injection attacks — today you built with your own hands the seed of that attack you’ll learn later. Run tools like this only on your own computer and in your own lab.


Once every box is checked, Step 51 is complete. Click the checkbox in the sidebar to save your progress.