Input/Output
Every program has three standard I/O streams: stdin (input), stdout (normal output), and stderr (error output). Understanding them is what unlocks the CLI's real power, connecting simple programs together to build something bigger.
Redirection
echo "hello" > out.txt # redirect stdout, overwrites out.txt
echo "world" >> out.txt # append instead of overwrite
sort < names.txt # redirect stdin FROM a file
cat missing.txt 2> err.log # redirect stderr (file descriptor 2) to a file
> and >> both aim a program's output at a file instead of your screen, the difference is whether it replaces or adds to existing content. < does the reverse, feeding a file's contents in as if you'd typed them.
Pipes
A pipe (|) connects one program's stdout directly to the next program's stdin, no temp file needed:
cat access.log | grep "ERROR" | wc -l
Read this left to right: print the log file, filter to lines containing "ERROR", count how many lines are left. Each command does one small job well, and piping chains them into something none of them could do alone, this is the core Unix philosophy.
Arguments and flags recap
grep -i "error" access.log # -i = case-insensitive flag
grep -c "error" access.log # -c = count matches instead of printing them
Most CLI tools accept flags to change their behavior without changing what you're fundamentally asking them to do, always check --help when you need a tool to behave slightly differently than its default.