Power editing & text processing
vim/vi mastery, and advanced sed & awk.
When you get paged at 2am and SSH (Secure Shell, the encrypted remote-login protocol) into a box to fix a broken config or read a log that is racing past, there is no mouse and no graphical editor waiting for you. There is a terminal, and three tools that ship on almost every Linux machine ever built: vim (a modal text editor, and its near-identical ancestor vi), sed (the stream editor), and awk (a tiny programming language for columns of text, named after its authors Aho, Weinberger, and Kernighan). The engineer who is fluent with them is several times faster than the one who fights them, and speed during a live incident is not a luxury.
This lesson is the power-user layer. There is no long list of commands to memorize here. What you want is the grammar and the idioms that let you build the exact edit or the exact report you need, on the spot, from parts you already know.
Vim Speaks In Verbs And Motions
Vim's real power is that its commands compose like a sentence: a verb plus a target. You do not learn ten thousand commands. You learn a handful of verbs, a handful of ways to describe a target, and you snap them together. The verbs are operators: d to delete, c to change (delete, then drop you into insert mode to type the replacement), y to yank (copy). Targets come in two flavors. Motions say 'from here to there': w to the next word, $ to the end of the line, } down to the next blank line. Text objects name a whole thing regardless of where your cursor sits inside it: iw is the inner word, i" is the text inside a pair of quotes, ip is a paragraph.
Snap a verb onto a target and you get a precise edit. dw deletes to the next word. ci" changes whatever is inside the quotes, like telling a mover to take everything inside the box no matter where you are standing in the room. dap deletes a whole paragraph. A number in front multiplies the whole thing, so 3dd deletes three lines. The single most valuable key is the dot: . repeats your last change. u undoes it, Ctrl-R redoes it. Learn this grammar and you stop recalling commands and start composing them.
d c y verbs: delete, change (delete + insert), yank (copy)w $ } 0 motions: next word, end of line, next blank line, start of lineiw i" ip a( text objects: inner word, inside quotes, a paragraph, a parens pairdw delete from the cursor to the next wordciw change the whole word under the cursorci" change the text inside the quotesd$ delete to the end of the linedap delete a paragraph (and its trailing blank line)yi( yank everything inside the parentheses3dd delete 3 lines>ip indent this paragraph. repeat the last changeu Ctrl-R undo redo
Moving And Editing At Speed
Building the edit is half the job. Getting your cursor to the right spot without hammering the arrow keys is the other half. Jump a word at a time with w and b. Fly to a character on the current line with f followed by that character. Go to line 42 with :42 or 42G. Land on the matching bracket with %, which is how you check that a JSON (JavaScript Object Notation, a common structured-data format) block or a shell if/fi pair is balanced. Search with /pattern, then n for the next hit and N for the previous. To start typing fast, A appends at the end of the line and o opens a fresh line below.
Visual mode selects first, then acts. v selects characters, V selects whole lines, and Ctrl-V selects a block, a rectangle of columns. Block-select down a file, press I, type once, hit Esc, and your text appears at the front of every selected line at once, which is how you comment out twenty lines in a few keystrokes. When you want to change every occurrence in the file, drop to the command line. :%s/old/new/g replaces all of them, adding c (:%s/old/new/gc) makes vim confirm each one, :g/DEBUG/d deletes every line matching DEBUG, and :10,20s/^/# / comments out lines 10 through 20.
w b jump forward / back one wordf{char} jump to the next {char} on this line:42 42G go to line 42% jump to the matching ( ) { } [ ]/error search; n = next match, N = previousA append at end of line o open a new line belowv V Ctrl-V select: characters / whole lines / a block (column)then I types on every selected line, Esc applies it:%s/old/new/g replace every match in the file:%s/old/new/gc ...asking you to confirm each one:g/DEBUG/d delete every line that matches DEBUG:10,20s/^/# / comment out lines 10 through 20
A short config file makes all of this stick, and it lives in your home directory as .vimrc. The setting worth calling out for defenders is set list, which paints normally invisible characters onto the screen. A configuration file written in YAML (a whitespace-sensitive settings format where spaces and tabs actually change the meaning) that 'looks correct' but refuses to parse often has a literal tab where spaces belong, a trailing space, or a non-breaking space that rode in from a copy-paste out of a web page. Turn on set list and those characters stop hiding.
set number " show line numbersset incsearch hlsearch " search as you type, highlight all matchesset list listchars=tab:»·,trail:·,nbsp:␣syntax on
Sed: One Scripted Pass Over The Stream
sed is a worker on an assembly line. Text flows past one line at a time, sed performs the scripted operation you handed it on each line, and the line moves on. It never loads the whole file into memory, so it chews through a multi-gigabyte log without breaking a sweat. The operation you already know is substitution, s/old/new/, but sed does far more than swap words.
You can restrict any operation to an address: a single line number, a pattern, or a range between two patterns. The d command deletes matching lines. Stripping the comment and blank lines out of a config shows you what is actually set, which is the fastest way to audit a service you did not configure yourself. Here is every real setting in a stock SSH server config, with the noise removed.
Give sed a range of two patterns with -n (quiet) and p (print) and it prints only the slice between them. On a log where dozens of requests interleave, that pulls one request's whole story out of the noise without opening the file.
Backreferences are how sed remembers pieces of a match and rebuilds them in a new order. Wrap parts of the pattern in parentheses (in extended mode, -E) and refer back to them as \1, \2, \3. Reordering a date is the classic drill, but the same move reshapes log fields, config keys, anything with structure. GNU sed (the version of sed that ships on nearly every Linux distribution) also takes an I flag for case-insensitive matching, so s/error/ERROR/gI catches Error, ERROR, and error in a single pass.
One sed pass also scrubs secrets before you paste a log into a ticket or a chat channel. Match the sensitive value, keep its label, replace the rest. The character class [^ &]+ says 'everything up to the next space or ampersand', so the value dies but the surrounding fields survive.
Awk: A Spreadsheet That Runs A Program
awk treats text like a spreadsheet and runs a tiny program on every row. Each line is a record, split into fields you reach as $1, $2, and so on up to $NF (the last field on the line). NR is the current record number, the running line count. You hand awk a pattern and an action in braces: for every line matching the pattern, run the action. That is the entire model, and it retires a surprising number of throwaway shell scripts.
Here is the one-liner every defender should keep in muscle memory. On Linux an account whose user ID number is 0 has root's powers, no exceptions, and there should be exactly one such account: root. The file /etc/passwd stores that ID as the third colon-separated field, so tell awk the separator is a colon with -F: and print the name of any account whose third field is 0.
If a second name ever shows up in that output, someone gave an account root's powers behind your back, and you have just found the backdoor. Flip the test to $3 >= 1000 and you get the human login accounts instead, because everything below 1000 is reserved for the system's own daemons and service accounts. Those low-numbered accounts are the ones to inspect next: a daemon account carrying a login shell of /bin/bash rather than /usr/sbin/nologin is worth a second look, because a background service has no reason to log in interactively.
Associative arrays are where awk earns its keep. An associative array is a bucket you can index by any string, including text like an IP (Internet Protocol) address, not only numbers. That lets you total something per address, per user, or per status code in a single pass over a file. Sum the bytes sent (field 10 of a standard web access log) grouped by the client address (field 1) to find who is pulling the most data off your server.
A BEGIN block runs before the first line and an END block runs after the last, which is where you print a summary. Count your server errors and total your traffic in one sweep, then format it with printf the way a C program would. In a standard access log the status code lands in field 9 and the byte count in field 10, so a single pass gives you both numbers.
Point the same thinking at an authentication log and you get a brute-force detector for free. Every failed SSH login writes a line reading 'Failed password ... from <IP> ...'. Walk the fields, grab the address that follows the word from, and rank the offenders by how many times they knocked.
That ranked list is your block-list candidate and your incident timeline in one shot. The attacker sees a wall of failed guesses. You see the source address, sorted by how hard they tried, ready to feed into a firewall rule.
Two habits make all of this permanent. Run vimtutor once, start to finish. It is a built-in, thirty-minute guided practice of the verb-plus-target grammar, and it pays back for the rest of your career. And keep every sed and awk transformation honest: print to the screen before you write with -i, and the moment a one-liner grows past two operations, move it into a small script file where a teammate can read it, review it, and run it again during the next incident. These tools do exactly what you tell them, no more and no less, so the pattern you verify is the pattern you can trust.
Try this
Work through “Awk: A Spreadsheet That Runs A Program” yourself on a sandbox you can throw away, following the commands above in order. Then break one step deliberately and re-run, so you have seen the failure before it finds you.
Takeaway
The trap worth remembering here: vim is not a forensics tool. Check that on your own systems before you need to, because it is cheaper to find on a quiet afternoon than during an incident.