Shell Basics: Navigation, Pipes & Redirection
The shell is the interface between you and the Linux kernel — and the single most used tool in a DevOps day. Learn what a shell is, how bash compares to zsh and fish, how stdin/stdout/stderr work, and master pipes, redirection, exit codes, PATH lookup and tab completion so you can chain commands into powerful one-liners.
What is this?
The shell is a program that reads the commands you type and turns them into actions performed by the kernel — running programs, moving files, starting services. It is also a tiny programming language with variables, conditionals and loops, which is why nearly every server admin writes shell one-liners and scripts every single day.
Why do you need it?
- The shell is the universal remote control for Linux: no matter which distro, cloud or container, the same bash commands work.
- Composing commands with pipes and redirection lets you solve in one line what would take a GUI several clicks — and it scales to thousands of servers.
- Understanding streams and exit codes is the foundation for debugging: every script, cron job and CI pipeline reports success or failure the same way.
- Shell fluency lets you read others' scripts, runbooks and CI files with confidence instead of copying them blindly.
- Almost every higher-level tool — Ansible, Kubernetes, Dockerfiles — ultimately runs shell commands, so shell knowledge never goes stale.
Mental model
A translator who turns your orders into precise instructions for the staff
The shell turning your commands into kernel requests
You speak in short phrases (ls, grep, systemctl restart nginx) and the shell translates them into the exact system calls the kernel needs, then reports back with results or errors. Change the translator (bash, zsh, fish) and the language stays recognisably the same.
How it works
- The shell reads a line, expands variables, wildcards and aliases, then splits it into a command name and its arguments.
- The command name is resolved by checking aliases, builtins, then every directory listed in $PATH — in order — until a matching binary or script is found.
- Every process starts with three file descriptors: stdin (0), stdout (1) and stderr (2). Pipes and redirection simply re-wire these between processes.
- The shell forks a child process for external commands, waits for it to finish, then records its exit status in the special variable $? (0 = success).
- A pipe (|) connects the stdout of the left process to the stdin of the right one, letting small focused programs be chained into a single data flow.
How a command flows from your keyboard to a result, and how streams are wired.
Key commands
echo "Hello, Linux"The echo builtin prints its arguments to standard output.
Hello, Linux
ls -lList files in the current directory in long format.
total 12 -rw-r--r-- 1 dev dev 22 Aug 8 10:00 notes.txt -rw-r--r-- 1 dev dev 120 Aug 8 10:02 todo.txt
echo $?Print the exit status of the previous command. 0 means it succeeded.
0
echo $PATHShow the directories the shell searches, in order, when you type a command name.
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
type cdReveal that cd is a shell builtin, not an external program.
cd is a shell builtin
ps aux | grep nginxPipe the full process table into grep to keep only lines mentioning nginx.
root 12345 0.0 0.1 123456 7890 ? Ss Aug07 0:00 nginx: master process
Examples
One pipeline that reads, transforms and saves data
# Count how many times each user logged in, keep the top 5, save itgrep 'session opened' /var/log/auth.log \ | awk '{print $1}' \ | sort | uniq -c | sort -rn \ | head -n 5 > top-logins.txt # Verify the resultcat top-logins.txtEach stage does exactly one job: grep keeps login lines, awk extracts the username, sort/uniq counts them, sort -rn ranks descending, and head keeps the top five. The final > redirects the whole result into a file instead of the screen.
In production
- One-liners for log triage: tail -f app.log | grep -i error | awk '{print $3}' instantly isolates failing requests.
- Cron jobs and systemd units wrap commands in redirects so stdout and stderr land in a log file you can audit.
- CI pipelines pipe test output into reporters: npm test 2>&1 | tee results.txt keeps both the screen and a file updated.
- Ansible, Dockerfiles and Kubernetes init containers all execute shell commands under the hood, so shell skills map directly to those tools.
Best practices
- Read commands before running them: use man <cmd> and <cmd> --help to check flags first.
- Let the shell complete for you — Tab for commands and paths, double-Tab to list ambiguous matches.
- Redirect stderr explicitly when you intentionally discard errors, so you never mask real problems.
- Quote arguments that contain spaces or wildcard characters to prevent accidental expansion.
- Check $? (or better, chain with && and ||) whenever a command must succeed before the next runs.
Common mistakes
- Using > when you mean >>, overwriting a log or config file instead of appending to it.
- Forgetting that 2> and > are separate streams, so errors still appear even after redirecting stdout.
- Putting the redirection or pipe in the wrong order, e.g. cmd 2>&1 > file which merges stderr into the old stdout.
- Typing a command name and getting "command not found" because $PATH does not include the script directory.
Common issues
command not found: myappThe binary is not in any directory listed in $PATH, or it is a script in the current directory (which is often not on PATH).
Run ./myapp for local scripts, or add the directory with export PATH="$PATH:/opt/myapp/bin" in ~/.bashrc.
Permission denied when running a scriptThe file has no execute bit, or is on a filesystem mounted with noexec.
chmod +x script.sh, or run it with bash script.sh. For noexec mounts, move the file to a normal location.
File was empty after I redirected outputThe command failed but you only redirected stdout, so the error went to stderr and the file was created empty.
Redirect both streams: cmd > out.log 2>&1, then inspect the log.
Debugging tips
- echo $? immediately after a failing command tells you whether it exited cleanly (0) or with an error code.
- Run commands with set -x in a script, or use bash -x script.sh, to see every line as it executes.
- ls -la and cat are your first move: confirm the file exists, is readable and has the content you expect.
- When a pipeline produces nothing, test each stage separately and then join them one at a time.
Interview checkpoint
Hands-on lab
- Navigate the filesystem with pwd, ls and cd
- Compose commands with pipes and filters
- Redirect stdout and stderr to files, overwriting and appending
- Read exit codes with $? and chain commands conditionally
Navigate, pipe and redirect like a DevOps engineer
12 min · beginner
Quick quiz
Which symbol redirects standard output to a file, overwriting it?
What does the 2 in 2> represent?
After a command fails, echo $? prints a non-zero number.
What does the pipe symbol (|) do in ls -la | wc -l?
Which stream does echo "hi" >> notes.txt use by default?
You run find / -name "*.conf" and the screen floods with "Permission denied" errors, burying the real matches. What is the cleanest fix?
Cheat sheet
pwdPrint working directoryls -laList all files with detailscd ~Go to your home directorycd -Go to the previous directoryclearClear the terminal screencmd > fileRedirect stdout, overwritecmd >> fileRedirect stdout, appendcmd 2> err.logRedirect stderr onlycmd > file 2>&1Redirect both streams to one filecmd 2>/dev/nullDiscard error messagescmd < input.txtFeed a file as stdina | bFeed stdout of a into stdin of bgrep patternKeep lines matching a patternsort | uniq -cCount unique lineshead -n 5First 5 linestail -fFollow a growing file (logs)wc -lCount linesecho $?Exit status of the last command (0 = ok)echo $PATHDirectories searched for commandstype cmdIs it an alias, builtin or binary?which cmdPath of the binary that runsalias ll="ls -la"Create a shortcutTabAutocomplete commands, files and flags