---
title: Mastering Linux Commands: A Practical Guide for Developers and AI Engineers
description: Eight reads before you restart a slow API: load, memory, disk, inodes, listeners, DNS, one request, and the log tail.
url: https://www.factualminds.com/blog/mastering-linux-commands/
datePublished: 2026-10-11T00:00:00.000Z
dateModified: 2026-10-11T00:00:00.000Z
author: palaniappan-p
category: DevOps & CI/CD
tags: linux, bash, devops, debugging
---

# Mastering Linux Commands: A Practical Guide for Developers and AI Engineers

> Eight reads before you restart a slow API: load, memory, disk, inodes, listeners, DNS, one request, and the log tail.

On 11 October 2026 the lab script on this Mac printed `uname=Darwin 27.0.0 arm64`, `bash=GNU bash, version 5.3.20(1)-release`, `ls_family=not_gnu`, `systemd=absent`, and `rg=present`. `df -h /` showed the root volume at 11% capacity with 105Gi available. That number describes one workstation, not a production server.

Eight reads come before you restart a slow API: load, memory, disk, inodes, listeners, DNS, one request, and the log tail. Restarting first throws away the evidence.

> **What broke** — `ls --version` on this Darwin host exited with `unrecognized option` and printed BSD `ls` usage. A command an agent copied from a GNU coreutils page failed immediately. The fix is to read the local `ls` help or install GNU coreutils as `gls`, not to assume the flag exists.

> **Reproduce this** — Run `bash examples/architecture-blog-2026/mastering-developer-tools/mastering-linux-commands/check-host.sh`. Expected lines: `ls_family=`, `systemd=`, and `lab=ok`. On macOS, `not_gnu` and `absent` are normal. Published copy: [/examples/architecture-blog-2026/mastering-developer-tools/mastering-linux-commands/check-host.sh](/examples/architecture-blog-2026/mastering-developer-tools/mastering-linux-commands/check-host.sh).

We recommend `set -euo pipefail` in scripts you keep, and an interactive shell without `set -e`. The trade-off: `-e` stops a script at the first failure, which is what you want in automation, and it surprises you in an interactive session when a test command is meant to fail.

## Why shell skill still matters

An agent can propose `rm -rf node_modules` or `kill -9` the API pid. You need to see the expanded path, the real pid, and whether the disk is full before you agree. The shell is also how you read logs on a host that has no agent installed.

## Shell mechanics that change what a command does

Bash built-ins (`cd`, `export`, `exit`, `jobs`) run inside the shell. External programs (`/bin/ls`, `rg`) are separate processes. `type cd` and `type ls` show which is which.

Quoting:

- `'single quotes'` pass the text literally.
- `"double quotes"` allow `$variables` and command substitution.
- Unquoted `*` expands to file names. An empty match can become a literal `*` or, with `nullglob`, an empty argument. Echo the command before you run it when the path includes a glob.

Exit status is `$?` immediately after the command. `0` means success. A pipeline's status is the last command unless `set -o pipefail` is on. With `pipefail`, any failed stage fails the pipeline. Chain with `&&` when the second command should run only after success, and `||` for a fallback. `;` runs the next command either way.

Redirects: `>` truncates a file. `>>` appends. `2>` is stderr. `>` on an existing file replaces it. **Potentially destructive.** `noclobber` (`set -o noclobber`) makes `>` fail if the file exists. There is no trash folder.

`man bash` is the manual for the shell on this machine. GNU Bash is documented at [gnu.org/software/bash/manual](https://www.gnu.org/software/bash/manual/).

## Installation and what is already there

You do not install `ls`. You install missing tools, and you check the family first.

Context: the lab script above. Read-only.

```bash
uname -srm
bash --version
type ls
command -v systemctl || echo "systemd tools absent"
command -v rg || echo "ripgrep absent"
```

- Linux: coreutils, findutils, and grep come from the distro. `apt`, `dnf`, and `apk` are not interchangeable. Read that distro's docs before a system upgrade.
- macOS: BSD userland plus a Bash you may have installed separately. This host's `/bin/bash` may be older than the Bash 5.3.20 reported by `bash --version` if `bash` on `PATH` is Homebrew. `type -a bash` shows every copy.
- Windows: use WSL for these commands. PowerShell aliases (`ls` as `Get-ChildItem`) are a different language. Run the lab inside the Linux environment you mean to operate.

`man ls` or `ls --help` (GNU) documents flags. BSD `ls` has no `--help` in the GNU sense. The lab's `ls_family` line is the check.

## Files and inspection

| Task | Command | Risk |
| --- | --- | --- |
| Where you are | `pwd -P` | **Read-only** |
| List | `ls -la` | **Read-only** |
| Change directory | `cd` | Shell state only |
| Make a directory | `mkdir -p dir/sub` | **Local change** |
| Copy | `cp -a SRC DEST` | **Local change**. Overwrites DEST. |
| Move | `mv SRC DEST` | **Local change**. Overwrites DEST. |
| Delete a file | `rm FILE` | **Potentially destructive** |
| Recursive delete | `rm -r DIR` | **Potentially destructive** |
| Disk type of a path | `df -h PATH` | **Read-only** |
| File type | `file PATH` | **Read-only** |
| Metadata | `stat PATH` | **Read-only**. Flags differ on BSD vs GNU. |
| Pager | `less PATH` | **Read-only** |
| Head and tail | `head`, `tail -n 50` | **Read-only** |
| Follow a log | `tail -f FILE` | **Read-only** |
| Counts | `wc -l FILE` | **Read-only** |

`pwd -P` resolves symlinks. `pwd` alone may show the logical path.

`rm -r` does not prompt unless you pass `-i` or the shell aliases `rm` to `rm -i`. Check `type rm`. Alias or not, echo the path first:

```bash
echo /path/you/mean
ls -ld /path/you/mean
```

If the variable is empty, `rm -r "$dir"` can target the current directory or fail. With `set -u`, an unset variable aborts the script. Prefer that.

Archives: `tar -tzf file.tar.gz` lists a tarball and extracts nothing. `tar -xzf` extracts. **Local change.** List first.

Links: `ln -s TARGET LINK` creates a symlink. `ls -l` shows the target. A relative symlink breaks when the link is moved.

## Search

| Task | Tool | Notes |
| --- | --- | --- |
| Find files | `find DIR -name '*.log'` | POSIX. `-delete` is **destructive**. |
| Search content | `grep -R -n PATTERN DIR` | GNU and BSD differ on `-P`. |
| Faster search | `rg PATTERN DIR` | Optional. Present on the lab host. |
| Sort and unique | `sort FILE`, `uniq -c` | `uniq` expects sorted input. |
| Columns | `cut -d, -f1` | Text only. |
| Translate | `tr '[:upper:]' '[:lower:]'` | Bytes, not a parser. |
| Streams | `xargs` | Splits on spaces unless `-0`. |
| Line edits | `sed`, `awk` | GNU and BSD `sed -i` differ. |

`find DIR -type f -name '*.log' -print` is read-only. `find ... -exec rm {} \;` deletes. **Potentially destructive.** Use `-print` and read the list before `-exec` or `-delete`.

`xargs` runs a command on arguments from stdin. `xargs rm` is how a bad search becomes a delete. Prefer `xargs -r` on GNU (do not run if stdin is empty) and null-delimited pairs: `find ... -print0 | xargs -0`.

`rg` is not part of POSIX. If `command -v rg` fails, use `grep`.

## Permissions

`ls -l` shows mode, owner, group, size. `id` shows your uid, gid, and groups. `chmod` and `chown` change metadata. **Local change**, and on a shared host they change who can read data.

`chmod 644` is owner read/write, others read. `chmod 600` is owner only. `chmod -R 777` makes a tree world-writable. Do not use it as a fix for a container that should drop root. The [Docker](/blog/mastering-docker-commands/) and [Kubernetes](/blog/mastering-kubernetes-commands/) articles cover the runtime side.

`sudo -n true` checks whether passwordless sudo works, and does not run your command. If it fails, you need a password or you are not in sudoers. `sudo` logs on many distros. It is not a way to skip reading the error.

ACLs (`getfacl` / `setfacl`) exist on some Linux filesystems and not on a default macOS APFS workflow. If `getfacl` is missing, you do not have that tool. Do not invent an ACL to explain a permission error.

`umask` prints the mask for new files. A umask of `022` creates files as 644 and directories as 755, subject to the creating program.

## Processes, memory, disk, network

| Question | Linux (typical) | macOS (this host) | Risk |
| --- | --- | --- | --- |
| Load and CPU | `uptime`, `top -bn1` or `ps aux` | `uptime`, `top -l 1` | **Read-only** |
| Memory | `free -h` | `memory_pressure` or `vm_stat` | **Read-only** |
| Disk space | `df -h` | `df -h` | **Read-only** |
| Inodes | `df -i` | `df -i` (column layout differs) | **Read-only** |
| Directory size | `du -sh DIR` | `du -sh DIR` | **Read-only** |
| Listeners | `ss -lntp` | `netstat -anv` or `lsof -nP -iTCP -sTCP:LISTEN` | **Read-only** |
| DNS | `getent hosts NAME` or `dig NAME` | `dig NAME` if installed | **Read-only** |
| HTTP | `curl -sS -o /dev/null -w '%{http_code}\n' URL` | same, if curl is installed | **Read-only** for GET |

`free` is not on macOS. The lab host has no `systemctl`, so service status is not `systemctl status`. Launchctl is the Mac equivalent and is outside this article's Linux service section.

`kill PID` sends SIGTERM. The process can catch it and shut down. `kill -9 PID` sends SIGKILL. The kernel stops the process without cleanup. Identify the command line first. Killing a database or a queue worker during a write is how you get a longer outage.

`fuser` and `lsof` show who holds a file or port. Useful when a deploy says the port is taken. Read-only until you kill something.

## SSH and files between hosts

`ssh -G HOST` prints the effective SSH config and does not connect. **Read-only.**

`ssh HOST 'uptime'` runs one command. That remote command has the remote user's privileges. Read it before you approve an agent that generated it.

`scp` and `sftp` copy files. `rsync -n` is a dry run. Drop `-n` only after the file list looks right. **Remote mutation** when the destination is another host.

Do not pipe `curl` into `bash` for an install script you have not read. Download, read, then run. A coding agent that suggests `curl URL | bash` is asking you to execute unseen code.

## Logs and services

On a host where `command -v systemctl` succeeds, systemd is the service manager. [systemd manuals](https://www.freedesktop.org/software/systemd/man/) document:

```bash
systemctl status SERVICE
systemctl cat SERVICE
journalctl -u SERVICE -n 100 --no-pager
```

Those are **read-only**. `systemctl restart` is a **remote or local mutation** of the running service. Restart after you have the eight reads, not before.

`systemctl --user` is a different bus from system services. Check which one the unit belongs to.

Hosts without systemd (containers based on Alpine openrc, older Amazon Linux variants, macOS) will not have these commands. The lab prints `systemd=absent` in that case. Use the supervisor that host actually runs: the process manager in the container image, `launchd` on macOS, or the platform's service tool. Do not install systemd inside a container to get `journalctl`.

Cron: `crontab -l` lists a user's crontab and does not edit it. `crontab -e` edits. Package timers on systemd are `systemctl list-timers`.

Boot: `journalctl -b` is the current boot on systemd. `last -x` shows shutdowns where the `last` command exists.

## Packages, env, checksums

Package installs change the system and can start services. **Local change**, sometimes **potential cost** if the host is metered. Prefer the distro's package manager over a random shell installer.

`env` and `printenv` dump the environment. Secrets are often in that dump. Do not paste `env` into a ticket. Ask for one variable: `printenv PATH`.

`sha256sum FILE` on GNU, `shasum -a 256 FILE` on macOS. Compare checksums from the vendor's site, not from the same page that offered the binary if you do not trust that page.

`gzip -t FILE` tests an archive and does not extract.

## Scenario: a catalog API is slow, and you do not restart it yet

Work on the host that runs the process, or from a bastion with SSH. Read-only until a human decides otherwise.

1. `uptime` for load average versus CPU count (`nproc` on Linux, `sysctl -n hw.ncpu` on macOS).
2. Memory: `free -h` on Linux. Swap activity means you are past RAM.
3. `df -h` and `df -i`. A full disk or a full inode table stops writes and can stall logs.
4. `ps` sorted by CPU or RSS. Name the pid and the command. A runaway is evidence. Killing it is a second decision.
5. Listeners: is the API port open on the expected address?
6. DNS: does the database hostname resolve to the address you expect?
7. One request: `curl` with a timeout (`curl --max-time 5`) and the HTTP code. A hang is different from an HTTP 500.
8. Logs: `tail` or `journalctl -u` for the last errors. Look for connection refused, timeout, and disk errors.

If the host is on AWS and the process is a container or a Lambda, move to [AWS CLI](/blog/mastering-aws-cli/), [Docker](/blog/mastering-docker-commands/), or [Kubernetes](/blog/mastering-kubernetes-commands/) with the host notes in hand. Distributed tracing is covered in [debugging production AWS systems](/blog/debug-production-distributed-aws-systems/).

## Safety list

- Recursive delete: `echo` the path, `ls -ld` it, then `rm`. Refuse an empty variable.
- `sudo`: identify the user with `id` first.
- `chmod` and `chown`: prefer a specific mode over `-R 777`.
- Globs: `echo` the expansion.
- `find -exec` and `xargs`: print the list before you delete.
- `>` overwrites. Point it at a new file name when you are unsure.
- `kill`: SIGTERM, then check the process is gone, then SIGKILL if you accept the lack of cleanup.
- Piped remote scripts: read the file, then run it.

## Working with a coding agent

Ask the agent to propose the read-only command and to explain the field you will look at (`%iused`, `load average`, HTTP code). Approve `rm`, `chmod -R`, `kill -9`, package upgrades, and `sudo` only after the preview. Run `echo` on any command that contains a glob or a variable. Then run the command yourself if it is production.

The agent's permission dialog is not file-system permission. `sudo` and IAM are separate. See [AI agent tools](/blog/mastering-ai-agent-tools/).

## Five labs

1. Run `check-host.sh`. Record `ls_family` and `systemd`. That is your local baseline.
2. In `/tmp`, `mkdir`, `cp`, `mv`, and `rm` one file you created. `ls -l` after each step.
3. `find /tmp -name 'fm-lab-*' -print` and confirm it prints nothing you do not recognize. Do not add `-delete`.
4. `ps` and find your shell's pid. Do not kill it. Write down the command line so you can see how easy it is to target the wrong pid.
5. `curl --max-time 5 -sS -o /dev/null -w '%{http_code}\n' https://example.com` and read the code. Expected: a three-digit HTTP status, often 200. If curl is missing, the lesson is that the tool is optional and you install it on purpose.

Progression: navigation and quoting, then read-only inspection, then process and disk diagnosis, then service restarts only after the eight reads.

## What this post does not cover

Performance tuning of a specific database, eBPF, and SELinux policy authoring. Container images and kubectl are the next two articles. It also does not document every flag of `awk`.

## What to do this week

1. Run the lab script on your laptop and on one non-production Linux host. Keep the two outputs. They will differ.
2. Add `echo` before any generated `rm` or `chmod -R`.
3. Find where the API logs live before the next incident.
4. If the API runs in AWS, pair this list with the [AWS CLI](/blog/mastering-aws-cli/) identity check.

## Quick reference

| I need to | Command | Risk |
| --- | --- | --- |
| Know the OS | `uname -srm` | **Read-only** |
| See a full disk | `df -h` and `df -i` | **Read-only** |
| See who listens | `ss` or `lsof` | **Read-only** |
| Page a file | `less` | **Read-only** |
| Delete | `rm` after `ls` | **Potentially destructive** |
| Service logs on systemd | `journalctl -u SERVICE` | **Read-only** |

You should be able to tell a builtin from an external command, refuse a recursive delete you have not previewed, and collect the eight reads before a restart.

## Further reading

- [GNU coreutils manual](https://www.gnu.org/software/coreutils/manual/coreutils.html)
- [Linux man-pages](https://man7.org/linux/man-pages/)
- [Bash manual](https://www.gnu.org/software/bash/manual/)
- [systemd](https://www.freedesktop.org/software/systemd/man/)
- Series: [Git](/blog/mastering-git-commands/), [AWS CLI](/blog/mastering-aws-cli/), [Docker](/blog/mastering-docker-commands/), [Kubernetes](/blog/mastering-kubernetes-commands/), [Bedrock CLIs](/blog/mastering-bedrock-cli/), [AI agent tools](/blog/mastering-ai-agent-tools/)

[Contact us](/contact-us/) or see [DevOps pipeline setup](/services/devops-pipeline-setup/) if you want this inspection habit in a runbook your on-call can follow.

## FAQ

### When should you not run rm -rf on a path an agent suggested?
When you have not printed the expanded path with echo, and when the path is empty, /, or a parent of the repo. Recursive delete is a local or remote data loss depending on the machine. Preview with ls on the exact path first.


### Do Linux commands work the same on macOS?
No. macOS ships BSD userland. ls --version fails there. sed -i and grep -P differ. This page was checked on Darwin 27.0.0 with Bash 5.3.20, where ls is not GNU and systemctl is absent. On a systemd host, systemctl and journalctl exist. Confirm with the lab script.


### Is sudo a way to fix permission denied?
sudo runs the command as root. That can hide a wrong path or a service account problem. Read the error, ls -l the file, and id the user first. Use sudo when the operation is supposed to be privileged, not as a retry.


### What should I check before killing a process?
The pid, the command line, the parent, and whether it is a worker that will be restarted by a supervisor. ps and /proc/PID/cmdline (Linux) or ps -p PID -o args= (macOS) identify it. kill sends SIGTERM by default. kill -9 skips cleanup.


### Does this page list every Linux command?
No. It covers the commands developers and operators use to inspect a host and to avoid the destructive ones. The manuals are man and the GNU coreutils manual.


---

*Source: https://www.factualminds.com/blog/mastering-linux-commands/*
