Every way to talk to the operating system
Files, paths and directories, arguments and environment variables, standard streams, child processes, signals, sockets, and calling the OS directly. The standard library door for each.
Name the thing you need from outside the program, then use the
standard library's door for it before reaching for a crate or unsafe.
- Data that should outlive the program → a file (
std::fs), named withPath/PathBuf, never by gluing strings together. If a crash mid-save would corrupt it, write a temporary file and rename. - Instructions from whoever started the program → command-line
arguments (
std::env::args, or clap for anything real) and environment variables (std::env::var). - Output → results to standard output, messages and progress to standard error, and an exit code a script can test.
- Another program's help →
std::process::Command, with pipes if you feed it input or read its output as it arrives. - Being told to stop (Ctrl-C, a container shutting down) → a signal handler that sets a flag, then a graceful shutdown.
- Another machine → a TCP or UDP socket, or HTTP on top of one.
- Something the standard library doesn't wrap → a crate like
nixorwindows-sysfirst; your ownexterndeclaration andunsafelast.
Files and directories
Section
Reading and writing files
fs::read_to_string for small files, a BufReader for big ones.
Section
Paths
Path and PathBuf, joined and taken apart the same way on every OS.
Section
Directories
Listing, creating and walking a tree.
Section
Metadata and permissions
Size, times and permission bits, and where Unix and Windows differ.
Section
Errors and edge cases
Missing files, permission errors, and the atomic replace.
tempfile for scratch files; mmap when a huge file should look like a slice.
The process itself
Section
Arguments and environment
env::args, env::var, and why argument 0 is the program.
Section
Standard streams
stdin, stdout and stderr, locked and buffered.
Formal. A process has three standard streams: standard input,
standard output (println!, io::stdout()), and standard error
(eprintln!, io::stderr()). Shells redirect and pipe standard output
(>, |) while standard error still goes to the terminal, and the
process's exit status (0 for success, non-zero for failure) is how
scripts and other programs learn whether it worked. io::stdout() is
line-buffered; lock it (stdout().lock()) or wrap it in a BufWriter
for heavy output.
In plain English. Your program's results go out one door and its complaints go out another, so someone saving the results to a file still sees the complaints on screen. The exit number is the one-word summary: 0 means "it worked".
Example. mytool > out.txt puts println! lines in the file while
an eprintln!("warning: ...") still appears in the terminal.
Why this rule exists. Command-line programs are joined together by pipes and scripts; mixing messages into the data, or reporting failure with status 0, breaks every program downstream.
Results on standard output so they can be piped; everything else on standard error.
Section
Signals and shutdown
Catch Ctrl-C, finish the current job, then exit.
Other programs
Section
Running other programs
Command, its arguments passed separately so nothing is ever shell-parsed.
Section
Pipes and child processes
Feed a child's input and read its output while it runs.
Other machines
Section
TCP client and server
TcpListener and TcpStream from the standard library.
Section
UDP
Single datagrams with no connection, for when losing one is acceptable.
Underneath the standard library
Section
Where Rust meets the OS
System calls, file descriptors, and the crates that wrap what std doesn't.
Section
Calling C from Rust
The last door, an extern block and unsafe.
Section
no_std, with no OS at all
What's left of the standard library when there's no operating system to ask.