Four hundred lines of build output, and the failure is on line 212. Scrolling for the word "error" gets you there eventually. There is a faster way to ask.
The idea
The The program behind the terminal window. It reads what you type, runs the right command, and shows you the result. is a small language for joining programs together. Each command reads some text, writes some text, and finishes with a number that says whether it worked. Learn to send one command's output into the next, stop a sequence when a step fails, and search a stream of text, and you can ask the exact question you want answered instead of reading whatever the computer printed.
pnpm build | grep "error" → exit status
──────────── ▼ ───────────── ──────────
writes 400 lines the pipe reads them, prints this is GREP's
of output carries only matching lines status, not the
the text build's. 0 here
means grep found
a match.How it works
- The pipe,
|.git log --oneline | head -20handsgit log's output tohead, so you see the last twenty commits instead of all nine hundred. Nothing is saved to disk. The text moves left to right. - Chaining with
&&.pnpm typecheck && pnpm testruns the tests only if the typecheck succeeded. Compare;, which runs the second command regardless. If you have ever watched a test suite pass on code that does not compile, you wanted&&. - Every command finishes with a number. Zero means it worked. Anything else means it failed, and the number sometimes says how..
Type
echo $?right after a command to see it. Zero meaning success is backwards from most people's guess, and it is why&&behaves as it does. grep. It prints the lines matching a pattern.grep -rn "DATABASE_URL" src/searches every file undersrc/, recursively, printing the file name and line number of each hit. That answers "where is this used" in two seconds.--help. Read it before pasting a A short option you add to a command, like-ror--json, that changes how it behaves. you do not recognise. Some commands answer with a short list, some open the manual in a pager, andqleaves a pager.- Backgrounding. A trailing
&, as inpnpm dev &, starts the command and gives you your prompt back.jobslists what is running,fgbrings one to the front, andCtrl-Cthen stops it. The job still prints into the same terminal, so a chatty dev server scribbles over what you type. For anything long-running, a second terminal tab is better.
On Windows. These are bash and zsh moves, and PowerShell is a different
language. && is a parse error in Windows PowerShell 5.1, the version built into
Windows, and works only in 7 and later. $? is a true/false value there, so the
exit code you want is $LASTEXITCODE. There is no grep (Select-String) and
no head (Select-Object -First 20). Trailing & has worked since PowerShell
6, but starts a background job in a separate process rather than a command you
can pull to the front: Get-Job lists them, Receive-Job -Wait hands you the
output, and there is no fg. WSL and Git Bash give you a real bash on Windows,
the shortest path to these examples working as printed.
What to do
-
Next time a build fails, capture the whole run and search the capture.
codepnpm build > build.log 2>&1; echo "exit status: $?" grep -n -i -E "error|failed|cannot" -A 3 build.log> build.logsends the output to a file instead of the screen and2>&1sends the error output to the same file. The;is deliberate: theechohas to run whether the build passed or failed. In the search,-iignores case,-Elets|mean "or" inside the pattern, and-A 3prints the three lines after each hit, where the filename and the explanation live. Trust the exit status over the grep output. A pipeline reports the status of its last command, sopnpm build | grep erroranswers a question about grep. Zero matches print nothing and look exactly like success, and compilers disagree about the word: Next.js saysFailed to compile., pnpm saysELIFECYCLE. -
Replace the next two commands you run in sequence with one
&&chain.pnpm typecheck && pnpm testis a safe one to start on. Keepgit add -A && git commitout of your habits:-Astages every untracked file in the repository, including the.envyour.gitignorehappens to miss, and a pushed commit is hard to unpublish. Rungit status, then stage the files you meant, by name. -
Pick one command you use blind and read its help. Expect two shapes.
git log --helpprints nothing and opens the full manual in a pager, so pressqto get out;git log -hgives the short flag list.curl --helpshows a dozen or so common options, depending on your version, and says at the bottom that it has hidden the rest, which needcurl --help all.
Where it breaks
grep matches text, so it has no idea what your code means. Searching for
user hits comments, variable names, and the word "user" inside a string. It
gives you a short list of places to look, and you still have to look.
Chaining is also a way to build something dangerous quickly. A command that
would have made you pause alone gets less attention as the fourth link in a
chain, and an AI assistant will happily compose a long one. Before running a
chain, find the step that touches something real, a file, a database, a server,
and read that one first. Anything with rm, --force, or a production hostname
in it deserves the pause you would have given it on its own.