Technology - Non SAP

Linux Command Line — The Mental Model for Developers

Most developers learn the terminal the same way. Something breaks on a server, a colleague pastes a command into Slack, and you run it without really understanding what it does. It works. You move on. The next time something breaks, you do the same thing again.

The problem is not the commands. The problem is that without a mental model, every terminal session feels like guesswork. You know the incantations but not the logic behind them.

This post does what the command cheatsheets do not — it explains how Linux thinks. Once the model clicks, the commands stop being magic and start making sense on their own.

🔗 Related Reading

Git — The Mental Model — the same mental-model approach applied to version control. Read this next.
Docker and Containers — The Why — Docker uses the Linux filesystem and process model directly. This post makes that click.

Terminal, shell, command line — three things people conflate

Before anything else, the terminology needs to be right. These three terms get used interchangeably, but they are different things.

The terminal is the application — the window you open. On macOS it is Terminal or iTerm. On Linux it is GNOME Terminal, Konsole or similar. It is just a program that displays text input and output.

The shell is the program running inside the terminal. It takes what you type, interprets it, and talks to the operating system. The most common shells are Bash (default on most Linux distros) and Zsh (default on macOS since 2019). For everything in this post, bash and zsh behave identically.

The command line is the interface type itself — text-based input. The terminal hosts the shell, which gives you a command line.

Why does this matter? Because when your shell configuration breaks, you fix it in a different place than when your terminal application breaks. Knowing which layer has the problem saves time.

📌 Key Takeaway

Terminal = the window. Shell = the program inside it. Command line = the style of interface. You configure them separately.

The filesystem — how Linux thinks about storage

This is the part most tutorials rush past, and it is the part that causes the most confusion.

Linux has one filesystem tree. Everything — every file, every device, every directory — hangs off a single root, represented by a forward slash: /. There are no drive letters like C:\ or D:. There is only /.

The Filesystem Hierarchy Standard (FHS) defines what lives where. You do not need to memorise all of it. You need to know the directories you will actually encounter.

DirectoryWhat lives thereWhen you encounter it
/The root. Everything starts here.Rarely — you navigate from here but do not store things directly in /
/homeYour user’s files. /home/rakesh is the home directory for user rakesh.Every time you work with your own files. ~ is a shortcut to your home dir.
/etcSystem-wide configuration files. nginx.conf, ssh/sshd_config, hosts.When you configure services or troubleshoot a broken config.
/varVariable data — things that change at runtime. Logs live in /var/log.When you are reading logs to debug a problem.
/tmpTemporary files. Cleared on reboot. Any process can write here.When you need scratch space. Do not store anything important here.
/usrUser programs and libraries. Most installed software lands in /usr/bin or /usr/local/bin.When you install or look for a program’s binary.
/binEssential system binaries. ls, cp, cat — commands needed for the system to function.You usually do not touch this directly. It just needs to be on your PATH.

One more principle that shapes everything: in Linux, almost everything is a file. Devices are represented as files in /dev. Running processes are exposed as files in /proc. Sockets and pipes are files. This means you can interact with hardware and processes using the same file-reading tools you use for text files.

Linux filesystem tree diagram on white background showing root directory with seven key subdirectories: home, etc, var, tmp, usr, bin, and dev, each labelled with its purpose

Once the tree structure makes sense, navigation commands become obvious. You are always somewhere in the tree, and these commands let you see where you are and move around.

CommandWhat it doesExample
pwdPrint working directory — shows your current location in the tree.pwd → /home/rakesh/projects
lsList contents of a directory. Add -la for full detail including hidden files.ls -la /etc
cdChange directory. cd .. moves up one level. cd ~ goes home. cd - returns to the previous dir.cd /var/log
mkdirMake a new directory. Add -p to create nested directories in one command.mkdir -p projects/api/src
cpCopy a file or directory. Add -r to copy directories recursively.cp config.yaml config.yaml.bak
mvMove or rename. Moving within the same filesystem is instant — it just updates a pointer.mv old-name.txt new-name.txt
rmRemove files. rm -rf removes directories recursively. There is no trash — this is permanent.rm -rf /tmp/build-artifacts

Two path styles exist: absolute paths start from / and describe the full location (/home/rakesh/projects). Relative paths start from where you are right now (../config or ./scripts/start.sh). The dot shortcuts matter: . means the current directory, .. means one level up, ~ means your home directory.

⚠️ Warning

rm -rf has no confirmation and no undo. Running rm -rf / on a server has destroyed production environments. Always double-check what you are removing before pressing enter.

Reading files — what you actually need

Most of the time at the command line, you are reading files — configs, logs, code output. A small set of commands covers almost all of it.

CommandWhat it doesWhen to use it
catPrint a file’s contents to the screen in one go.Short files, quick checks. Not useful for logs — use less.
lessPage through a file — scroll with arrow keys, search with /, quit with q.Any file longer than a screen. The right tool for reading large logs.
headPrint the first N lines (default 10). head -n 20 file.log.Checking what a file starts with without loading all of it.
tailPrint the last N lines. tail -f follows a live file as it grows.tail -f /var/log/nginx/access.log is the one you reach for first in production.
nanoA simple text editor that runs in the terminal. Ctrl+O to save, Ctrl+X to exit.Quick edits to config files on a server. Not for writing code — use your IDE for that.

💡 Practical Tip

tail -f is the most useful command on this list for day-to-day work. Attach it to any log file and you get a live stream of what the application is doing. Combine it with grep to filter for errors only: tail -f app.log | grep ERROR

Pipes and searching — where Linux philosophy becomes a superpower

Here is the design principle behind the Linux command line: each tool does one thing well and produces text output. The pipe operator | connects tools together, feeding the output of one command as the input to the next.

This sounds modest. The practical implication is significant: you can build powerful data pipelines by chaining simple commands, without writing a single line of code.

📌 Key Takeaway

The pipe | takes the output of the command on the left and feeds it as input to the command on the right. It is the single most useful concept in the Linux command line.

grep — search inside files

grep searches for a pattern inside a file or stream and prints matching lines. It is the fastest way to find what you need in a large log.

grep ‘ERROR’ /var/log/app.log # find all lines containing ERROR

grep -i ‘timeout’ /var/log/app.log # case-insensitive search

grep -n ‘NullPointerException’ app.log # show line numbers

grep -r ‘API_KEY’ ./config/ # search recursively in a directory

find — locate files by name or type

find searches the filesystem for files matching criteria. Unlike grep (which searches inside files), find searches for the files themselves.

find . -name ‘*.log’ # find all .log files from here

find /etc -name ‘nginx.conf’ # find nginx config

find . -type f -mtime -1 # files modified in the last day

Combining with pipes

This is where it comes together. You can chain grep, find, sort, wc and any other text tool to answer specific questions without writing a script.

cat /var/log/app.log | grep ‘ERROR’ | wc -l # count error lines

ls -la /var/log | grep ‘.log’ | sort -k5 -n # list logs sorted by size

ps aux | grep nginx # is nginx running?

Linux pipe flow diagram on white background showing three commands chained with pipe operators: cat app.log feeds into grep ERROR feeds into wc -l with the output showing 42 error lines

Permissions — why access errors happen

Every file and directory in Linux has permissions attached to it. When you see permission denied, the permissions model is the reason. Understanding it stops you from blindly running sudo on everything — which is how permissions problems get made worse.

Permissions are assigned to three groups: the owner (the user who created the file), the group (a named group of users), and others (everyone else). Each group gets three permission bits: r (read), w (write), x (execute).

When you run ls -la, you see the permission string in the first column:

-rwxr-xr— 1 rakesh developers 4096 Jun 7 script.sh

Breaking that string down: the first character is the file type (- for file, d for directory, l for symlink). Then three characters each for owner, group, others.

In the example above: the owner can read, write and execute (rwx). The group can read and execute but not write (r-x). Others can only read (r—).

Permission bitOctal valueOn a fileOn a directory
r (read)4View the file’s contentsList the directory’s contents (ls)
w (write)2Modify the fileCreate or delete files inside the directory
x (execute)1Run the file as a programEnter the directory (cd into it)

chmod and common values

chmod changes permissions. You can use symbolic notation — chmod u+x script.sh adds execute for the owner — or octal notation like chmod 755 script.sh.

The octal values are additive: r=4, w=2, x=1. So 7 = rwx, 5 = r-x, 4 = r—. Three digits cover owner, group and others in that order.

chmod valueWhat it meansUse it for
755Owner: rwx. Group: r-x. Others: r-x.Executable scripts, directories you want others to enter but not write to.
644Owner: rw-. Group: r—. Others: r—.Regular files — readable by all, writable only by the owner.
600Owner: rw-. Group: ---. Others: ---.Private files — SSH keys, credentials. No access for anyone else.
777Everyone: rwx.Avoid this. It means anyone can read, modify and execute the file. Almost never the right choice.

⚠️ Warning

chmod 777 is the most common permissions mistake. It feels like a quick fix for a permission denied error. It works — but it gives every user on the system full access to the file. On shared servers or containers, this is a security problem. Use 755 or 644 unless you have a specific reason for something else.

chown and sudo

chown changes the owner of a file: chown rakesh:developers script.sh assigns the file to user rakesh and group developers. You usually need to be root (or use sudo) to change ownership.

sudo runs a single command as the superuser. It does not permanently elevate your session. If you find yourself running sudo on everything just to make things work, the real problem is usually incorrect file ownership — fix the ownership, not the permissions.

Linux file permissions breakdown diagram on white background showing the string -rwxr-xr-- divided into three groups: owner with rwx, group with r-x and others with r--, plus octal reference showing 755

Processes — what is running and how to stop it

Everything running on a Linux system is a process. Each process has a numeric ID — a PID. The process commands are what you reach for when something is hanging, consuming too much memory, or refusing to stop.

CommandWhat it doesPractical use

| ps aux | List all running processes with PID, CPU and memory usage. | ps aux | grep nginx — find the PID of a specific process. |

| top / htop | Live, updating view of all running processes. htop has a better UI and mouse support. | Use htop for interactive monitoring. Install it — it is not always pre-installed but worth having. | | kill [PID] | Send a signal to a process. Default is SIGTERM — asks the process to stop gracefully. | kill 1234 — graceful stop. kill -9 1234 — force kill, no cleanup. | | Ctrl+C | Send SIGINT to the process running in the current terminal session — stops it. | The first thing to try when a command is running and you want it to stop. | | Ctrl+Z | Suspend the current process and return to the shell. The process is paused, not killed. | Use bg to resume it in the background, fg to bring it back to the foreground. |

💡 Practical Tip

Try kill [PID] (SIGTERM) before kill -9 [PID] (SIGKILL). SIGTERM lets the process clean up — flush logs, close connections, release locks. SIGKILL bypasses all of that. Use -9 only when SIGTERM does not work.

At a glance — the Linux command line mental model

ConceptOne-line summary
TerminalThe application window — hosts the shell. iTerm, GNOME Terminal, etc.
ShellThe program inside the terminal — interprets commands. Bash or Zsh for most developers.
Filesystem root (/)The single starting point for all files on a Linux system. No drive letters — one tree.
/etcSystem configuration files — nginx, ssh, hosts. Edit these to configure services.
/var/logLog files — where applications write their output. Your first stop when debugging.
Absolute pathFull path from root: /home/rakesh/projects/app.js. Always works regardless of where you are.
Relative pathPath from your current directory: ../config or ./scripts/start.sh. Shorter but context-dependent.

| Pipe ( | ) | Connects commands — passes the output of one as the input to the next. The key composability primitive. |

| grep | Search for a pattern in a file or stream. The first tool to reach for when reading logs. | | Permissions (rwx) | Three bits for owner, group, others. r=4, w=2, x=1. 755 = owner full, group/others read+execute. | | chmod | Change file permissions. chmod 755 script.sh. Use 644 for regular files, 600 for secrets. | | sudo | Run one command as superuser. Fixes permission denied — but fix ownership first before reaching for sudo. |

| PID | Process ID — every running process has one. Use ps aux | grep [name] to find it. |

| kill / kill -9 | Send SIGTERM (graceful) or SIGKILL (force) to a process by PID. Try graceful first. |

What to take away

The terminal feels hostile until you understand what it is — a text interface to a system structured around a single tree, where everything is a file. Once that model is in your head, the commands stop being a list to memorise and start being the obvious tools for the job.

The pipe is the thing most developers underestimate. It is not just syntax. It is a design philosophy — small, focused tools that compose. grep, sort, wc, find are each trivial on their own. Chained together, they let you answer questions that would otherwise need a script.

One more thing: permission denied is almost always an ownership or permissions problem, not a signal to reach for sudo. Understand what the permissions string says, find the mismatch, and fix the root cause. That habit will save you from a class of mistakes that cause real damage on real servers.

✅ Best Practice

When you run a command you copied from somewhere, take 10 seconds to understand what it does before pressing enter. The mental model in this post is enough to evaluate most commands. Blind copy-paste is how production servers get broken.

🔗 Related Reading

Git — The Mental Model — git is used entirely from the command line. This post assumes the terminal knowledge you just built.
Docker and Containers — The Why — Docker containers run Linux under the hood. File paths, permissions and process management all apply.
How Kubernetes Works — The Mental Model — kubectl and cluster debugging live at the command line. The Linux fundamentals here are the foundation.
SQL Fundamentals — SQL databases on Linux are configured and debugged via the terminal. The patterns here apply directly.

Published on rakeshnarayan.com — Articles

URL: https://rakeshnarayan.com/articles/linux-command-line-the-mental-model-for-developers/