I Still Live in the Terminal

tacoda1 pts0 comments

Why I Still Live in the Terminal. The first Linux box I ever ran came on… | by Ian Johnson | Jun, 2026 | MediumSitemapOpen in appSign up<br>Sign in

Medium Logo

Get app<br>Write

Search

Sign up<br>Sign in

Why I Still Live in the Terminal

Ian Johnson

4 min read·<br>Just now

Listen

Share

The first Linux box I ever ran came on a stack of CDs in a paper sleeve — RedHat 6.2, borrowed from a friend in high school. The install took an hour and burned through two coasters. When it finally booted to a console prompt, I had no idea what to type. I learned ls. I learned cd. Then I tried something a book I had showed: cat /var/log/messages | grep error. Two commands, a vertical bar, and the answer fell out faster than any GUI tool on the machine could’ve produced it. I’ve been chasing that feeling ever since.<br>The first time pipes felt like cheating<br>Pipes are not a feature. They’re a worldview. The bar between two commands says whatever the first one wrote, the second one can read. No adapter, no integration, no plugin. The OS is the integration.<br>That night with the RedHat CDs, I didn’t have the vocabulary for it. I knew the answer arrived faster than it should have. A few months later I was chaining four commands. A year later I was writing shell scripts that wrapped the chains. The shape never left.<br>Text is the universal interface<br>Every Unix tool speaks lines. Stdin is a stream of bytes; stdout is a stream of bytes; the shell wires them together. That one rule replaces a thousand integrations. You don’t need a “GitHub for Jira” plugin if gh prints JSON and jq reads it. You don’t need a database GUI if psql prints rows and awk does the math.<br>The cost is real; text is a lossy carrier, and a tool that emits structured data through plain text always loses some shape on the way. The payoff is bigger. A new tool that emits lines slots into every existing pipeline I’ve ever written, the day it ships. No vendor has to bless the integration. The shell already did.<br>make is the constant<br>The first time I wrote a Makefile was for a C class in college. make called gcc, gcc produced a binary, the binary ran. The build command was make. The test command was make test. I never had to remember the flags.<br>Over ten years later, the Makefile in the project I’m working on right now calls docker compose instead of gcc. Different decade, different tool under the hood. Same two-letter command in my muscle memory. make run. make test. make migrate. The compiler changed; the wrapper did not.<br>Get Ian Johnson’s stories in your inbox

Join Medium for free to get updates from this writer.

Subscribe

Subscribe

Remember me for faster sign in

This is the part most people miss about IDEs. Every IDE button is a shell command underneath. The button is a convenience. The command is the contract. When I write the command into a make target, I get the same convenience — one keystroke — without the dependency on someone else’s UI shipping that button in the next release.<br>test:<br>docker compose run --rm app pytest

run:<br>docker compose up

shell:<br>docker compose run --rm app bashThree targets, eight lines. The IDE button that does the same thing is buried four menus deep and breaks when the project layout changes. The Makefile breaks the same day too, but I can fix it in the same window I work in.<br>The keyboard is the point<br>My hands stay on the home row. fzf to find a file. gd in Neovim to jump to a definition. A tmux pane for Claude, a pane for the test runner, a pane for git. No alt-tab. No mouse hand-off. No window manager wrestling.<br>The reason isn’t speed in the stopwatch sense. It’s latency between thought and action. The five-click version of a task gives the brain five chances to lose the thread. The aliased one-keystroke version gives it zero. A task I do every week (pull main, rebase my branch, push, open the PR) collapses into make pr. The script behind it is about a dozen lines I wrote over 8 years ago and have edited a handful of times since.<br>alias gco='git checkout'<br>alias gp='git push'<br>alias gst='git status -sb'<br>alias k='kubectl'<br>alias dc='docker compose'Five aliases, hundreds of fewer keystrokes a week. The math compounds the longer you stay.<br>I’ll use the GUI when it earns the slot<br>The terminal isn’t dogma. I open Chrome for the web. I open Figma when a designer hands me a file. I screenshare in Zoom because nobody wants to read my tmux layout. The test is whether the GUI returns something the CLI can’t: a rendered page, a pixel-perfect layout, or a human face. When the answer is yes, I use the GUI without ceremony. When the answer is no, I’m back in the terminal before the window finishes opening.<br>The split isn’t terminal good, GUI bad. It’s return value. Most engineering work returns text: code, logs, configs, queries, diffs, and so on. Text belongs in a text environment. The terminal is a text environment that’s been refined for fifty years. It’s not going to lose that race in my lifetime.<br>Find one click you do every week and replace it<br>Pick a task...

make terminal text command test first

Related Articles