Home·Terminal commands

Terminal command reference

227 commands with the flags people actually reach for and a worked example each

⌨️ Commands and flags are typed as-is, so they are never translated — only the explanations follow your language.

Files and directories32

Moving, deleting and finding. Some of these do not ask twice, which is why -i becomes a habit.

lsLists what a directory holds; names that begin with a dot stay hidden until you add -a.cdMoves the shell to another directory; it is a shell builtin, so a cd inside a script or subshell never moves your outer shell.pwdPrints the directory you are standing in; if you walked in through a symlink it shows the link path, and only -P gives the real one.mkdirCreates a directory; without -p it fails both when a parent is missing and when the directory already exists.rmdirDeletes a directory only when it is empty; anything inside makes it refuse, which is why people reach for rm -r.rmDeletes files for good — there is no trash can, and one stray space in rm -rf erases something you did not mean.cpCopies files or whole trees; whether the destination already exists decides if the source becomes that name or lands inside it.mvRenames or moves; without -i or -n it overwrites the target silently.touchBumps a file's timestamps to now and creates it empty if it is missing; it never touches the contents.catPrints files one after another; it dumps everything at once, so long files want less and cat file | grep is one pipe too many.lessPages through a file without loading all of it; / searches and q quits, and unlike more it never closes by itself at the end.headPrints the start of a file; give it several files and it inserts a header for each unless you pass -q.tailPrints the end of a file and keeps watching it with -f; only -F reopens the file after a log rotation.findWalks a directory tree testing every entry; quote the pattern as -name '*.log' or the shell expands it before find ever sees it.locateSearches a prebuilt index instead of the disk, so it answers instantly but cannot see files created since the last updatedb.treeDraws the directory structure as an indented picture; it is not installed by default on macOS or slim Linux images.duAdds up the disk space files actually occupy; it counts allocated blocks, so its total differs from the sum of file sizes and from df.dfReports used and free space per filesystem; a disk can run out of inodes while bytes remain, and only df -i shows that.lnGives a file another name; a symlink made with -s can point anywhere but breaks when the target moves, and a relative target is read from the link's own directory.statShows the inode record — size, permission bits, owner and the three timestamps; the format flag is -c on GNU but -f on BSD, where the GNU -f means something else entirely.fileWorks out a file's type from its contents rather than its name; it ignores the extension, which is how a .jpg that is really a PDF is caught.basenameStrips the directory part off a path and can drop a suffix too; it is pure string work and never checks whether the file exists.dirnameKeeps only the directory part of a path; with no slash in it the answer is a single dot, and like basename it only edits text.realpathTurns any path into one absolute path with symlinks and dots resolved; the macOS build is the BSD one, so GNU flags like --relative-to are absent.rsyncCopies only the differences between two trees, locally or over ssh; a trailing slash on the source means its contents, and leaving it off nests the directory one level deeper.mountAttaches a filesystem to a directory; whatever was already in the mountpoint is hidden rather than deleted and comes back when you unmount.umountDetaches a mounted filesystem; the name has no n in it, and it refuses with device is busy while any process still has a file or its working directory inside.readlinkPrints what a symlink points to, one hop only unless you add -f; on a file that is not a link it prints nothing and exits with an error.mktempCreates a temp file or directory with a name nobody can guess and prints its path; it never cleans up after itself, so pair it with a trap on exit.sha256sumPrints a file's SHA-256 fingerprint so you can tell whether a download arrived intact; a matching hash proves the bytes match, not that the source is trustworthy.truncateSets a file's length exactly: growing it only makes a sparse hole without allocating space, and shrinking throws the tail away with no warning.shredOverwrites a file's bytes before deleting it, but on SSDs and copy-on-write filesystems such as btrfs or APFS the old blocks may survive, so full-disk encryption is the real answer.

Text processing32

These were built to be piped together. Three joined commands are usually shorter than one that does everything.

grepPicks the lines that match a pattern; it reads basic regex by default, so + ? | and () need -E or a backslash to keep their meaning.sedEdits text line by line, most often with s/old/new/; the in-place -i differs between GNU and BSD, and without a trailing g only the first match on each line changes.awkSplits each line into fields and runs a little program over them; $0 is the whole line and $1 the first field, and the default separator is any run of whitespace, not one space.sortSorts lines; without -n it compares them as text so 10 comes before 9, and the locale decides the order unless you put LC_ALL=C in front.uniqCollapses only runs of identical neighbouring lines, not duplicates spread through the file, so it is nearly always used after sort.wcCounts lines, words and bytes; -l counts newline characters, so a final line with no newline is not counted.cutSlices out fixed fields or character positions; the delimiter is a single character and repeated delimiters are not merged, so whitespace-aligned columns are awk's job.pasteGlues files together side by side with a tab between them; unlike join it matches lines by position and never looks at their content.trReplaces or deletes characters one for one; it reads standard input only, so a file name as an argument fails and you must redirect with < or pipe into it.joinJoins two files on a shared field like a database join; both files must already be sorted on that field or lines silently drop out.commCompares two sorted files and prints three columns — only-left, only-right, in-both; unsorted input gives nonsense, and the flags hide columns rather than select them.diffShows what changed between two files; the unified -u form is what patch and code review expect, and it exits 1 when they differ, which stops a script running under set -e.patchApplies a diff to real files; -p decides how many leading path components to drop, and a git diff needs -p1 because of its a/ and b/ prefixes.teeCopies its input into a file and on to the screen at once; it is how you write to a root-owned file, because in sudo cmd > file the redirect is opened by your own shell.xargsTurns lines of input into arguments for another command; names with spaces break it unless both sides agree on NUL, meaning find -print0 with xargs -0.echoPrints its arguments and a newline; -e and backslash handling differ between shells and builds, so printf is the portable choice.printfFormats text from a template exactly like C's printf; it adds no newline of its own and reuses the format from the start while arguments remain.jqFilters and reshapes JSON with its own small language; it is often not installed by default, and -r is what strips the quotes from string output.columnPads fields so the columns line up like a table; repeated separators count as one, so a CSV with empty cells comes out shifted.foldHard-wraps long lines at a fixed width by inserting real newlines; without -s it cuts words in half, and unlike a terminal's soft wrap it changes the file itself.nlNumbers lines as it prints them; by default it skips blank lines, which is why its numbers disagree with an editor until you pass -b a.revReverses the characters within each line, not the order of the lines — that is tac's job.splitCuts a file into pieces; a header row stays only in the first piece, and the names end in aa, ab unless you pass -d for numbers.csplitSplits a file where a pattern appears rather than at a fixed size; the numbers it prints are byte counts, and {*} means repeat as often as it matches.expandTurns tab characters into spaces; a Makefile needs real tabs to work, so running expand on one breaks the build.shufPrints its input lines in random order; it is GNU coreutils and absent on macOS, where the usual stand-in sort -R groups equal lines together.tacPrints a file's lines from last to first; it is GNU coreutils, so macOS uses tail -r, and it is not rev, which reverses characters.stringsPulls printable text out of a binary; it grabs anything that looks like text, so most of the output is coincidence rather than meaning.iconvConverts text from one character encoding to another; it stops at the first byte it cannot map unless you add -c, and it cannot guess the input encoding for you.vimA modal editor: typing does nothing until you press i, and you leave with Esc then :wq to save or :q! to discard.nanoA plain full-screen editor with its commands printed at the bottom; the caret in ^O and ^X means Ctrl, not a literal character.base64Turns bytes into ASCII text and back so binary can travel through text-only channels; it is encoding, not encryption, and the decode flag is -d on GNU but -D on older macOS.

git45

The confusion is that undo has several shapes — moving where a branch points is not the same as adding a commit that reverses it.

git initTurns a folder into a new git repository; init alone tracks nothing, so add and commit still have to happen.git cloneCopies a remote repository with its history; a --depth 1 clone has no old commits and no other branches, so --unshallow is needed later.git configReads and writes git settings; without --global it only touches this repository, which is why a fresh clone forgets the setting.git init --bareCreates a repository with no working tree, meant only to be pushed to; you cannot edit files in it, but pushes never bounce off a checked-out branch.git addStages the file as it looks right now; editing it again after add leaves that change out, so you have to add once more.git commitRecords what is staged as one commit; -a picks up modified tracked files only, so brand-new files are left out.git statusShows what is staged, changed and untracked; untracked files are collapsed into folder names unless you add -uall.git diffShows only the changes you have not staged yet, which is why it looks empty right after git add — use --staged then.git logLists commit history newest first, but only the ancestors of the current HEAD — other branches need --all.git showPrints one commit with its message and diff; the <commit>:<path> form pulls out an old version of a file without touching your working copy.git blameMarks each line with the commit that last changed it; a pure reformat hides the real author, which is what -w and --ignore-rev are for.git branchLists, creates and deletes branches locally; deleting one leaves the remote copy alone, so the server still needs git push origin --delete.git checkoutThe old command for both switching branches and restoring files, split into switch and restore in git 2.23; checkout -- <file> erases uncommitted edits for good.git switchThe git 2.23 command that only moves between branches; it never rewrites file contents, which is what restore is for.git restoreThe git 2.23 command for putting file contents back; by default it overwrites your working file and the uncommitted edits are gone, while --staged only unstages.git mergeBrings the work of another branch into the current one; --squash records no merge, so git still counts that branch as unmerged afterwards.git rebaseReplays your commits on a new base; the hashes change, so never rebase a branch other people already pulled — merge there instead.git resetMoves the branch pointer to another commit: --soft keeps everything staged, --mixed (the default) also clears the staging area but leaves your edits in the files, and --hard throws those edits away too, unrecoverably.git revertUndoes a commit by adding a new opposite commit; it leaves history intact, unlike reset which moves the branch pointer, so anything already pushed should be reverted.git cherry-pickCopies a single commit onto the current branch as a new commit with a new hash, so merging that branch later can show the same change twice.git stashParks your unfinished changes and gives you a clean tree; untracked files stay behind unless you pass -u, and pop removes the entry while apply keeps it.git cleanDeletes untracked files, which git never had a copy of, so nothing comes back; -fdx also wipes ignored files such as a local .env, so run -n first.git remoteManages the names and URLs of remote repositories; it only records them, so nothing travels until you actually fetch or push.git fetchDownloads new commits without touching your files or branch, so a merge or rebase still has to follow, and branches deleted on the server linger until --prune.git pullRuns fetch and merge in one step, which is where surprise merge commits come from; --rebase or --ff-only prevents them.git pushSends your commits to a remote; --force overwrites the remote branch and can erase commits other people pushed, so use --force-with-lease, which refuses when the remote moved.git tagPuts a name such as a version on a commit; a plain git push does not carry tags, so the tag has to be pushed by name.git rmRemoves a file from the index and from disk; --cached keeps the file and only stops tracking, but the old content stays in history, so a leaked secret is still there.git mvMoves a file and stages the move in one step; git stores no rename, it guesses one from similar content, so a case-only rename needs -f on macOS and Windows.git ls-filesLists paths from the index rather than from disk, which makes it the reliable list to script over; -i cannot stand alone and needs -c or -o plus --exclude-standard.git update-indexEdits the index directly; the marks are local and never pushed, and the one that keeps your local edits to a tracked config file is --skip-worktree, not --assume-unchanged.git sparse-checkoutAdded in git 2.25, it keeps only the directories you name on disk; the history is still complete and cone mode takes directory names, not glob patterns.git reflogRemembers every position HEAD and your branches have had, which is where commits lost to reset --hard or a deleted branch turn up; entries expire after 90 days by default and exist only on your machine.git bisectHalves the range of commits to find the first bad one; you must finish with git bisect reset, or you stay parked on a detached commit.git describeNames the current commit from the nearest tag, as v1.2.0-5-gabc1234; it only sees annotated tags by default, so lightweight ones need --tags and a repository with no tag needs --always.git rev-parseTurns a name like HEAD or v1.2.0^ into a real hash and answers where the repository is; scripts get the branch name with --abbrev-ref HEAD, and outside a repository it exits with an error.git fsckChecks the object database and lists commits nothing points at, the second way to find work lost after a reset once the reflog entry is gone; it reports, it does not repair.git gcPacks loose objects and drops unreachable ones to shrink .git; --prune=now also throws away the commits the reflog was holding, which removes your safety net for undoing a reset.git archiveExports the files of one commit as a tar or zip; .git and untracked files are left out, which makes a cleaner release archive than zipping the folder.git applyApplies a diff file to your working tree; it makes no commit and ignores the author recorded in the patch, so mailed patches belong to am instead.git amTurns mailed patches into commits, keeping the original author and message; on failure it stops in the middle of the series, so you have to finish with --continue, --skip or --abort.git format-patchWrites one mail-shaped .patch file per commit for review by email; format-patch main means the commits after main, not main itself.git shortlogGroups commits by author and counts them, handy for release notes; one person with two email addresses counts twice unless a .mailmap merges them.git worktreeChecks out a second working folder from the same repository so you can build two branches at once without cloning again; the same branch cannot be checked out twice, and deleting the folder by hand leaves an entry until prune.git submodulePins another repository at one commit inside yours; a plain clone leaves the folder empty until update --init, and the parent tracks a commit, not a branch.

Processes and system36

What is running and what is eating the machine. Identifying it comes before killing it.

psTakes a one-off snapshot of the running processes; `ps aux` is the BSD spelling with no dash and `ps -ef` the POSIX one, and mixing the two is the usual mistake.topRedraws the process list every few seconds; its flags differ completely between platforms, so a single snapshot is `-b -n 1` on Linux and `-l 1` on macOS.htopA colourful, mouse-aware rewrite of top where F9 sends a signal directly, but it is not installed by default, so `apt install htop` or `brew install htop` comes first.killSends a signal to a PID to shut a process down; the default TERM lets it clean up, while `-9` cannot be caught, so open files and lock files are left behind.killallKills processes by name rather than by PID; the name must match the executable exactly, so `killall chrome` misses a process called "Google Chrome".pkillKills every process matching a pattern; without `-f` only the process name is compared, and a loose pattern takes down more than you meant, so run pgrep with the same pattern first.pgrepPrints just the PIDs a pattern matches, using exactly the same rules as pkill, which makes it the dry run to do before you kill anything.jobsA shell builtin that numbers the background jobs of this shell only, so jobs from another terminal never appear and you refer to them as `%1`, not by PID.bgResumes a job you stopped with Ctrl+Z, in the background; it still belongs to this shell, so closing the terminal takes it with you unless you used nohup or disown.fgBrings a background or stopped job back to the terminal; it only works on jobs of this shell, and you name them with a job number like `%1`, not a PID.nohupMakes a command ignore the hangup signal so it survives logout; it does not background anything, so you still add `&` yourself, and output piles up quietly in ./nohup.out.niceStarts a command with a lower CPU priority; the value runs from 19 (most yielding) to -20 (greediest), negative values need root, and it affects only CPU, not disk (that is ionice).reniceChanges the priority of a process that is already running; an ordinary user can only make it nicer, and taking the priority back again needs root.systemctlStarts, stops and inspects systemd services; `enable` only sets boot behaviour, so use `enable --now` to also start it, and run `daemon-reload` after editing a unit file.journalctlReads the binary log systemd collects; without /var/log/journal the log is wiped at reboot, and `-u` needs the unit's exact name.serviceA thin wrapper left over from the SysV era; on a systemd machine it simply forwards to systemctl and understands fewer verbs.crontabEdits the per-user schedule table; cron runs with almost no PATH and never reads your login profile, so write absolute paths, and `crontab -r` erases the whole table without asking.atRuns a command exactly once at a time you name; the atd daemon has to be running (often it is not even installed), and the output is mailed to you rather than printed.uptimeShows how long the machine has been up plus the load average; those three numbers are runnable processes averaged over 1, 5 and 15 minutes, not percentages, so 4.00 on a 4-core box means fully busy.freeCounts how much memory and swap are left on Linux; the column to read is available, not free, because cache is handed back on demand, and macOS has no free at all (use vm_stat).vmstatPrints memory, swap, disk and CPU counters at a fixed interval; throw away the first line, which is an average since boot rather than now, and look at the si/so and wa columns first.iostatShows per-disk throughput and how long requests wait; the first block is an average since boot, Linux needs the sysstat package, and macOS takes different flags such as `-w 1 -c 5`.lsblkLays out the disks and their partitions as a tree; it does not show unpartitioned free space (that is fdisk or parted), and it is Linux only, so macOS uses `diskutil list`.unameReports the kernel name, its release and the machine architecture; it will not tell you the distribution, for which you read /etc/os-release (or `sw_vers` on macOS), and `-o` is GNU only.hostnamePrints or sets this machine's name; `hostname web01` only lasts until the next reboot, so make it permanent with `hostnamectl` on Linux or `scutil --set HostName` on macOS, and `-I` for every IP is Linux only.datePrints the current time in any format you like and does date arithmetic; the format after `+` is the same everywhere, but shifting a date is `-d` on GNU and `-v` or `-j -f` on macOS/BSD.envPrints the whole environment, or runs one command with extra variables attached; those variables apply to that single run only and nothing is left behind in your shell.exportMarks a variable so child processes inherit it; it dies with this shell, so put it in ~/.bashrc or ~/.zshrc to keep it, and a bare `VAR=x` without export stays invisible to the programs you run.whichSearches PATH and tells you where the executable of that name lives; because it looks only at PATH it lies about aliases, functions and shell builtins, and the honest answer comes from `type -a` or `command -v`.typeAsks the shell itself what a name really is, whether alias, function, builtin or file, which is exactly what `which` cannot see because it only looks at PATH.lsofLists every open file and socket, which is how you answer "what is holding port 3000"; without sudo you only see your own processes, so an empty result does not mean the port is free.fuserFinds, and if you ask kills, whatever is using a file, a mount point or a port; `-k` sends SIGKILL with no chance to clean up, and it exists only on Linux (psmisc) since the macOS version has just `-cfu`.watchReruns the same command every few seconds and redraws the screen; quote anything with a pipe or a `*` in it, or the shell applies it once to watch itself, and macOS does not ship it.timeoutRuns a command under a time limit and cuts it off when the limit passes, exiting 124; the default signal is TERM, which a hung program can ignore, so add `-k` to follow with KILL (GNU coreutils, absent on macOS).stracePrints every system call a process makes, which is how you see where it is stuck; the output goes to stderr so redirect it with `2>&1`, it needs ptrace permission (usually sudo), and it is Linux only (macOS has dtruss).dmesgReads the kernel ring buffer, the first place to look after a disk or USB problem; it is a fixed-size buffer so older lines are already gone, and most distributions now require root (macOS uses `log show`).

Networking28

When a connection fails, these narrow down how far it got — name not resolving, no route, or a blocked port.

curlFetches a URL and prints the body to the terminal; unlike a browser it does not follow redirects without `-L`, so a 301 looks like an empty response.wgetDownloads a URL into a file and follows redirects on its own; that is the difference from curl, which prints to the terminal unless told otherwise, and macOS does not ship wget.pingSends ICMP echo requests to see whether a host answers and how long it takes; no answer does not mean it is down, because plenty of firewalls drop ICMP while TCP works fine.tracerouteLists the routers a packet passes on the way to a destination; a `* * *` line in the middle does not mean the path is broken, only that that router declines to answer.digAsks a DNS server directly and shows the records as they come back; it bypasses /etc/hosts and the system cache, so the answer can differ from what the browser sees, and some distributions need dnsutils or bind-utils installed first.nslookupThe older name-to-address lookup tool: it still runs, but its output layout and exit status are inconsistent enough to be useless in scripts, and dig has taken its place.hostAnswers a name lookup in two or three short lines of addresses and mail servers; it is the handiest for a quick check, but for the full record view you need dig.ssThe modern way to list open sockets on Linux, the successor to netstat and much faster on a busy host; note that `-p` only reveals the owning process when you are root.netstatThe old way to see sockets and the routing table; on Linux it has been handed over to ss and is often not installed at all, and although macOS keeps it, it cannot tell you which process owns a socket, so lsof answers that.ipThe single Linux command for addresses, routes and the neighbour table, replacing ifconfig, route and arp; anything you change with it is gone after a reboot unless you also write it into the network configuration.ifconfigThe old command for looking at and touching network interfaces; on Linux `ip addr` has replaced it, it may not even be installed, and it cannot show every address ip added — on macOS, though, it is still the real tool.routeReads and edits the kernel routing table, but on Linux it has given way to `ip route`, and on BSD/macOS the grammar is different altogether, such as `route -n get default`, so examples do not carry across.arpShows the table of MAC addresses for neighbours on the same local network; anything beyond the router is never in it, and on Linux `ip neigh` is the current tool.nc (netcat)Opens a raw TCP or UDP connection to see whether a port answers, and pipes bytes between two machines; three incompatible netcats share the name (OpenBSD, GNU, Nmap ncat), so `-z` or `-p` may simply not exist on yours.telnetOpens a plain TCP session in which everything travels in clear text, so it must never be used to log in (that is ssh); its remaining use is checking whether a port answers, and you leave with Ctrl+] then quit.sshOpens an encrypted shell on another machine; ssh flatly refuses a private key that others can read, so `chmod 600` it, and the port is `-p` here but `-P` in scp and sftp.ssh-keygenCreates a public and private key pair; only the `.pub` half ever goes on a server, and a key made without a passphrase is a plain file that anyone who copies it can log in with.ssh-copy-idAppends your public key to the server's ~/.ssh/authorized_keys so it stops asking for a password; password login has to still be open for that first run, and `-i` takes the `.pub` file, not the private key.sftpAn interactive file transfer tool riding on the ssh connection; the port flag is a capital `-P` rather than ssh's `-p`, and it cannot run remote shell commands, only its own put, get and ls.scpCopies files over ssh in one shot; the port is a capital `-P`, the remote side needs a colon in its path, and for anything large or repeated rsync is better because it skips unchanged files and resumes.iptablesEdits the live packet filter; rules are matched top to bottom and the first match wins, so a DROP appended after an ACCEPT never fires, the rules vanish at reboot unless saved, and setting the default policy to DROP before allowing port 22 locks you out of a remote machine.ufwA friendly wrapper around iptables on Debian and Ubuntu; allow SSH before you `enable` it or you cut the session you are sitting in, and Docker publishes ports straight into iptables where ufw rules do not cover them.tcpdumpCaptures the packets going past on the wire; it needs root, what to capture is written after the flags in its own filter syntax such as `port 443 and host x`, and capturing without a filter on a busy interface buries the terminal instantly.whoisLooks up the registration record of a domain or IP block; personal fields are mostly redacted now and every TLD server formats its reply its own way, so parsing that output in a script breaks easily.nmapSweeps a host to see which ports answer; `-sS` and `-O` need root, and scanning a machine you do not own is recorded as an attack in its logs and is illegal in some countries, so keep it to your own networks.openssl s_clientOpens a raw TLS connection so you can inspect the certificate and the handshake; leave out `-servername` and a server hosting many sites on one address hands you its default certificate, and without `< /dev/null` it sits there waiting for input.speedtestMeasures line speed by actually pushing traffic to a nearby server; it is not preinstalled on any system, and two different programs share the name (Ookla's speedtest and the Python speedtest-cli) with different flags.mtrMerges traceroute and ping into one continuously updated table, the right tool for intermittent packet loss; loss shown at a middle hop is usually just that router rate-limiting its replies, and only loss that continues to the final hop is real.

Archives14

Bundling and compressing are separate jobs: tar bundles, gzip shrinks, and .tar.gz is both.

tarBundles files into one archive but does not compress on its own — `-z` (gzip), `-j` (bzip2) and `-J` (xz) do that part — and you pick exactly one of `-c` to create, `-x` to extract or `-t` to list, keeping `-f` as the last flag so the archive name follows it directly.gzipCompresses a single file into .gz and, by default, deletes the original once it succeeds, so keep it with `-k` or by writing to stdout with `-c`; it never bundles several files, which is why tar comes first.gunzipUnpacks a .gz back to the original file and removes the .gz on success, so `-k` keeps it, `-f` is needed when a file of that name already exists, and `-c` streams the contents out without ever writing them to disk, exactly like zcat.zipUnlike tar it carries its own compression, and it is the format a Windows machine opens with no extra software; a directory needs `-r` or you archive the folder entry and nothing inside, and the password from `-e` is legacy ZipCrypto and weak.unzipExtracts a .zip, and without `-d` it empties straight into the current directory, so run `-l` first to see whether the archive has a top-level folder; names from older Windows zips need `-O CP932`, and a password given with `-P` is visible in your shell history and in ps.bzip2Squeezes harder than gzip but takes longer, and like gzip it deletes the original and leaves only the .bz2 unless you pass `-k`; the tar flag for it is `-j`, and decompressing is `-d`, which is what bunzip2 does.xzGives the smallest output of the three common formats but is slow and wants roughly 700 MB of memory at `-9`; it runs single-threaded unless you add `-T0`, it removes the original without `-k`, and the tar flag for it is a capital `-J`.zcatStreams what is inside a .gz to stdout without ever unpacking it to disk, which is how you grep a rotated log in place; `-f` lets plain uncompressed files through in the same pass, and bzip2, xz and zstd have their own bzcat, xzcat and zstdcat.7zTakes a verb first — `a` to add, `x` to extract with paths, `e` to flatten them, `l` to list — reads far more than .7z including zip, tar and rar, and packs tighter than most; the output directory goes right after `-o` with no space, and `-mhe=on` alongside `-p` is what also hides the file names.ddCopies block for block, which is how an installer image gets written to a device; whatever you name in `of=` is overwritten from block zero with no confirmation and no way back, so confirm the device with lsblk immediately before pressing Enter, use `bs=4M` for speed and `status=progress` (Ctrl+T on macOS) to watch it.splitCuts a big file into pieces; the default is by line count, 1000 at a time, so pass `-b 100M` when you meant size, the pieces are named xaa, xab and so on unless you give a prefix, and you glue them back with a single `cat part_* > file`, which works only because the suffixes sort in order.cpioAn older archiver that takes the list of names to pack from stdin, which is why find usually feeds it; `-o` writes an archive, `-i` extracts one, `-t` lists it, `-H newc` is the portable format initramfs images use, and `--no-absolute-filenames` stops an archive from someone else writing into absolute paths.zstdThe modern one: it reaches gzip’s size several times faster, and at `-19` it lands near xz sizes in a fraction of xz’s time; unlike gzip it keeps the source file by default (`--rm` deletes it), `-T0` uses every core, and tar calls it with `--zstd`.rarA proprietary format where only the extractor is free: creating an archive needs the paid rar binary, while `unrar x` — or `7z x` with nothing installed from RARLAB — unpacks one someone sent you, `x` keeping the stored paths and `e` flattening them, `-hp` hiding the file names too and `-v100m` splitting the archive into volumes.

Permissions15

Numeric and symbolic modes name the same thing: 755 and u=rwx,go=rx are the same permission.

chmodSets the permission bits on files and directories; chmod -R 755 makes plain files executable too, so use the capital X form to leave files alone.chownChanges a file's owner and group; only root may hand a file to someone else, which is why it almost always needs sudo.chgrpChanges only a file's group, which chown can also do with :group; unless you are root you may only assign a group you belong to.umaskDecides which permission bits are withheld from newly created files; it subtracts rather than grants, so 022 yields 644 for files and 755 for directories, and it never touches files that already exist.sudoRuns one command as another user, root by default; the redirect in sudo cmd > file is opened by your own shell, so it fails on a root-owned file and tee is the way.suBecomes another user with that user's own password, the opposite of sudo which asks for yours; leave off the dash and you keep your own PATH, the usual cause of command not found.idPrints the user and group ids a process runs with; id -u returning 0 means root, which is the standard way a script checks for administrator rights.groupsLists the groups a user belongs to; a group just added with usermod does not appear until the next login, because the list is fixed when the session starts.whoamiPrints the effective user name rather than the one you logged in as, so inside sudo or su it says root.passwdChanges a login password and stores its hash in /etc/shadow; macOS has almost none of the Linux flags and uses dscl or System Settings instead.getfaclPrints the access control list, the extra per-user rights beyond owner, group and others; it is Linux with the acl package, while macOS shows its own kind of ACL with ls -le.setfaclGrants rights to one extra user or group without changing the owner; once an ACL exists ls shows a + after the mode, and the mask entry can quietly cap what you granted.chattrSets filesystem-level attributes such as immutable; with +i even root must clear the flag before editing, and it works only on Linux filesystems like ext4, xfs and btrfs.xattrReads and removes extended attributes on macOS, most often com.apple.quarantine, the flag behind the app is damaged warning; Linux uses getfattr and setfattr instead.visudoEdits /etc/sudoers with a lock and a syntax check before saving; editing that file directly and getting it wrong locks everyone out of sudo, which is exactly what visudo prevents.

Packages and runtimes25

The question is always what goes where: inside this project, or on the whole machine.

npm installDownloads the dependencies package.json asks for into node_modules and updates package-lock.json; since npm 7 peer dependencies are installed too, and --production was replaced by --omit=dev.npm ciDeletes node_modules and installs exactly what package-lock.json says; it never edits the lockfile and fails outright when the lockfile and package.json disagree, which is why CI uses it instead of install.npm runRuns a command from the scripts section of package.json; arguments meant for the script need a bare -- first, and only start and test can be called without run.npm initCreates a package.json; npm init <name> is a different thing altogether, downloading and running create-<name> the way npx does.npxRuns a package binary, preferring node_modules/.bin and otherwise fetching it temporarily; because a typo can pull a stranger package from the registry, --no keeps it local-only.yarn addAdds a package and updates yarn.lock; plain yarn means install, and Yarn 2 dropped yarn global add, so one-off tools go through yarn dlx.pnpm addPuts the package in a shared store and links it into node_modules; at a workspace root pnpm refuses a plain add and wants -w or --filter to say where it goes.npm auditReports known vulnerabilities in the installed tree; fix --force will pull in breaking major versions, and warnings buried in dev-only dependencies often cannot be fixed at all.npm publishUploads the package to the registry; a scoped name is private by default so --access public is needed, and a version number can never be reused, so check the file list with --dry-run first.node --versionPrints the version of the node that comes first on PATH, which is why an editor terminal or a CI job can report a different one when a version manager is in play.nvm useSwitches which installed Node the current shell uses; the change lives in that shell only, so a new terminal or a CI job falls back to the default, and because nvm is a shell function a script or Makefile has to source nvm.sh first.brew installInstalls a prebuilt bottle on macOS and Linux; GUI applications need --cask, and moving to a newer version is the job of brew update and brew upgrade, not of install.apt-get installInstalls from the package list already on disk, so a stale list gives "Unable to locate package" until apt-get update runs; apt-get keeps a stable interface for scripts, while apt is the one meant for humans.apt updateRefreshes the package lists and nothing else, so apt upgrade has to follow to actually install anything; a fresh container has an empty list, which makes this the first command.dnf installInstalls from the enabled repositories and resolves dependencies, refreshing metadata on its own expiry so there is no separate update step as with apt; on RHEL 8 and later yum is a link to dnf, and Fedora 41 moved to dnf5.pacman -SInstalls a package from the sync repositories on Arch; because the distribution rolls, refreshing with -Sy and installing without upgrading creates a partial upgrade that breaks libraries, so use -Syu.pip installInstalls a package into whichever Python is active; calling it as python -m pip avoids the classic case of pip belonging to another interpreter, and since PEP 668 a system Python refuses installs outside a virtual environment.pip freezePrints every installed package with its exact version, ready to redirect into requirements.txt; it lists transitive dependencies as well as the ones you chose, so it has to be run inside the virtual environment.python -m venvCreates an isolated interpreter and site-packages inside one folder; creating it does nothing until you activate it or call .venv/bin/python directly, and the paths are baked in, so renaming the folder later breaks it.docker runCreates and starts a new container from an image every time, so running it twice gives you two containers and restarting an existing one is docker start; without -p nothing is reachable from the host, and without -v whatever it writes dies with the container.docker psLists only the containers running right now; one that exited straight after start is invisible until -a, which is where to look when docker run seems to have done nothing.docker buildBuilds an image from a Dockerfile; the trailing dot is the build context sent to the daemon, so a fat folder makes builds slow until .dockerignore trims it, and COPY can only see files inside that context.docker compose upStarts every service in compose.yaml as one project; the hyphenated docker-compose is the retired v1 while docker compose is the v2 plugin, and existing containers are reused unless you pass --build or --force-recreate.docker execRuns another process inside a container that is already running; it fails on a stopped one, and slim images have no bash, so you go in with sh.docker logsShows what the main process of the container wrote to stdout and stderr; an app that logs into a file inside the container shows nothing here, and the logs disappear with the container.

How to read this

  • Square brackets [ ] mark a part you may leave out.
  • An ellipsis … means you can list more than one.
  • Flags are case-sensitive — in some commands -r and -R do different things.

Questions

Q. Why are the command names not translated?

Because you type them as they are. A translated ls is a name the shell does not know. Flags stay for the same reason — only the explanations follow your language.

Q. The flags differ between macOS and Linux.

They do. macOS ships BSD tools, so some GNU flags are missing — sed -i wants an argument, ps does not take -ef. Where they diverge, the description says which platform it belongs to.

Q. How do I spot the commands that cannot be undone?

Their descriptions say so. rm does not use a trash can, dd overwrites a disk if of= is wrong, and git reset --hard and git clean -fd throw away uncommitted work.