Command-Line Notes

A short English companion to the Chinese pages: the handful of rules that explain most shell surprises, plus two lookup tables I keep coming back to. The full notes are in Chinese; these sections are the parts that read better in English.

1. Quoting, in three rules

Nearly every "why did my script do that" question comes down to how the shell split the line into words.

name="two  spaces"
printf '%s\n' $name      # "two spaces"   - collapsed
printf '%s\n' "$name"    # "two  spaces"  - preserved

The practical rule: always quote variable expansions unless you have a specific reason not to. The classic failure is a loop over files that breaks the first time someone uploads my report.txt.

2. Exit codes and strict mode

Zero means success, anything else is a failure. $? holds the status of the previous command, but every command overwrites it — including echo — so capture it immediately.

curl -fsS -o /dev/null http://example.com/health
rc=$?
[ "$rc" -eq 0 ] || echo "health check failed: $rc" >&2

Start non-trivial scripts with:

set -euo pipefail
FlagEffect
-eExit when a command fails (with exceptions: conditions, && lists, !).
-uError on an unset variable instead of expanding it to an empty string.
-o pipefailA pipeline fails if any stage fails, not just the last one.

Without pipefail, curl … | head reports success whenever head succeeds, which hides a broken download completely.

3. Pipeline patterns worth memorising

# Count lines by a key
awk '{print $1}' access.log | sort | uniq -c | sort -rn

# Keep the header, filter the rest
awk 'NR == 1 || $3 > 100' data.tsv

# Replace in place (GNU sed; BSD sed needs -i '')
sed -i 's/old/new/g' file

# Walk files safely, including names with spaces
find . -type f -name '*.log' -print0 | xargs -0 gzip

# Fail loudly if a variable is empty
: "${TOKEN:?TOKEN must be set}"

Two habits that prevent most data loss: run find … -print before adding -delete, and never parse ls output — use globs or find.

4. Undoing things in Git

SituationCommandWhat survives
Edited, not stagedgit restore <file>Nothing — the change is discarded
Staged, not committedgit restore --staged <file>The edit stays in the working tree
Committed, not pushedgit commit --amendSame changes, new commit object
Committed, not pushedgit reset --soft HEAD~1Changes return to the index
Already pushedgit revert <sha>History unchanged, a new inverse commit is added
Anything, within 90 daysgit reflogRecover a lost tip by hash

Never rewrite a branch other people have pulled. git push --force-with-lease is the least dangerous way to force, because it refuses when the remote has commits you have not seen.

5. HTTP status codes at a glance

CodeMeaningWhen to use it
200OKSuccessful read or update with a body
201CreatedAfter POST, with a Location header
204No ContentSuccess with nothing to return
301 / 308Moved permanentlyPermanent; browsers cache it for a long time
302 / 307Found / Temporary redirectUse 307 if the method and body must be preserved
304Not ModifiedAnswer to a conditional request; no body
401UnauthorizedMissing or invalid credentials
403ForbiddenAuthenticated but not allowed
404Not FoundThe resource does not exist
409ConflictConcurrent edit or state clash
429Too Many RequestsRate limited; include Retry-After
502 / 504Bad Gateway / Gateway TimeoutUpstream returned garbage / did not answer in time

Returning 200 with an error payload inside the body breaks caching, monitoring and retry logic all at once. Status codes are for infrastructure; business error codes belong in the body.

6. Where to go next

The Chinese pages go into much more detail, with worked examples and platform differences: