<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>grep — LowEndSpirit</title>
        <link>https://lowendspirit.com/</link>
        <pubDate>Sun, 23 Aug 2026 17:23:17 +0000</pubDate>
        <language>en</language>
            <description>grep — LowEndSpirit</description>
    <atom:link href="https://lowendspirit.com/discussions/tagged/grep/feed.rss" rel="self" type="application/rss+xml"/>
    <item>
        <title>sed vs awk vs grep: when to reach for which</title>
        <link>https://lowendspirit.com/discussion/11251/sed-vs-awk-vs-grep-when-to-reach-for-which</link>
        <pubDate>Sat, 22 Aug 2026 07:00:00 +0000</pubDate>
        <category>Blog</category>
        <dc:creator>mikho</dc:creator>
        <guid isPermaLink="false">11251@/discussions</guid>
        <description><![CDATA[<p>Every terminal tutorial teaches these three with the same tired example: <code>cat file | grep foo</code>. <br />
That's not a real task, it's a syntax demo.</p>

<p>On an actual VPS, the question isn't "how does grep work," it's "which of these three do I even use?" Here's how to answer that in about three seconds, using a real <code>access.log</code>.</p>

<p>Say your box just had a slow morning and you're digging through last night's nginx access log:</p>

<pre><code>203.0.113.14 - - [18/Aug/2026:03:12:01 +0000] "GET /wp-login.php HTTP/1.1" 404 162 0.002
198.51.100.7 - - [18/Aug/2026:03:14:22 +0000] "GET /api/v1/status HTTP/1.1" 200 48 0.014
198.51.100.7 - - [18/Aug/2026:03:14:23 +0000] "GET /api/v1/status HTTP/1.1" 200 48 0.011
203.0.113.14 - - [18/Aug/2026:03:15:40 +0000] "POST /xmlrpc.php HTTP/1.1" 404 162 0.002
192.0.2.55 - - [18/Aug/2026:03:20:10 +0000] "GET /api/v1/status HTTP/1.1" 200 48 3.821
192.0.2.55 - - [18/Aug/2026:03:20:15 +0000] "GET /api/v1/report?range=30d HTTP/1.1" 200 118402 1.204
198.51.100.7 - - [18/Aug/2026:03:22:01 +0000] "GET /api/v1/status HTTP/1.1" 200 48 0.009
203.0.113.14 - - [18/Aug/2026:03:23:55 +0000] "GET /.env HTTP/1.1" 404 162 0.001
192.0.2.55 - - [18/Aug/2026:03:25:30 +0000] "GET /api/v1/report?range=7d HTTP/1.1" 200 41200 0.412
</code></pre>

<p>The last column is response time in seconds, added by a custom log format. That's the line that pays off later.</p>

<h3>Question one: am I looking for lines, or looking at data inside them?</h3>

<p>If the answer is "I just need to find the lines," that's grep. Nothing else. You want every request that hit your status endpoint:</p>

<pre><code>$ grep '/api/v1/status' access.log

198.51.100.7 - - [18/Aug/2026:03:14:22 +0000] "GET /api/v1/status HTTP/1.1" 200 48 0.014
198.51.100.7 - - [18/Aug/2026:03:14:23 +0000] "GET /api/v1/status HTTP/1.1" 200 48 0.011
192.0.2.55 - - [18/Aug/2026:03:20:10 +0000] "GET /api/v1/status HTTP/1.1" 200 48 3.821
198.51.100.7 - - [18/Aug/2026:03:22:01 +0000] "GET /api/v1/status HTTP/1.1" 200 48 0.009
</code></pre>

<p>Four lines out of ten, full text, unmodified. That's the whole job of grep: a filter, not a processor. The moment you catch yourself piping grep's output into <code>cut</code> or <code>awk '{print $1}'</code> to pull a field back out, stop, you skipped a step. You didn't need lines, you needed data.</p>

<p><img src="https://lowendspirit.com/uploads/editor/xf/arvs39622270.webp" alt="LowEndSpirit - VPS Hosting and tech forum" title="" /></p>

<h3>Question two: do I need to compute something across fields?</h3>

<p>That 3.821-second response on line five is the actual problem, one request from 192.0.2.55 that took four thousand times longer than the others. Finding that by eye in a real log with fifty thousand lines isn't happening. This is awk's job, because awk thinks in fields and running totals, not just matched lines:</p>

<pre><code>$ awk '{ bytes[$1]+=$10; if ($NF+0 &gt; slow[$1]) slow[$1]=$NF }
       END { for (ip in bytes) printf "%-15s bytes=%-8d slowest=%.3fs\n", ip, bytes[ip], slow[ip] }' access.log

198.51.100.7    bytes=144      slowest=0.014s
192.0.2.55      bytes=159650   slowest=3.821s
203.0.113.14    bytes=648      slowest=0.002s
</code></pre>

<p>One pass over the file, running two accumulators keyed by IP, and the answer falls out: 192.0.2.55 is both your heaviest bandwidth consumer and the source of that slow request. grep could never have told you that. <br />
It doesn't do arithmetic, and it doesn't remember anything between lines. awk does both by default. <br />
That's the actual dividing line between them: grep answers "which," awk answers "how much," "how many," or "what's the total."<br />
<img src="https://lowendspirit.com/uploads/editor/5k/vtizrd5cfq64.webp" alt="LowEndSpirit - VPS Hosting and tech forum" title="" /></p>

<h3>Question three: do I need to change the file itself?</h3>

<p>Neither grep nor awk touches your file; they both just read it and print to stdout. If the task is "the box just got renamed, and I need to update the nginx config to match," that's sed, because sed's whole reason to exist is in-place transformation:</p>

<pre><code>$ cat nginx-site.conf
server {
    listen 80;
    server_name oldbox.example.net www.oldbox.example.net;
    ...
    proxy_set_header Host oldbox.example.net;
}

$ sed -i.bak 's/oldbox\.example\.net/newbox.example.net/g' nginx-site.conf

$ cat nginx-site.conf
server {
    listen 80;
    server_name newbox.example.net www.newbox.example.net;
    ...
    proxy_set_header Host newbox.example.net;
}
</code></pre>

<p>Three occurrences, one command, and the <code>.bak</code> suffix means the original is still sitting right next to it if the regex was wrong. (It wasn't, but check anyway, every time, no exceptions.)<br />
<img src="https://lowendspirit.com/uploads/editor/te/ex4mxd37qpc0.webp" alt="LowEndSpirit - VPS Hosting and tech forum" title="" /></p>

<h3>The actual decision tree</h3>

<p>Not three bullet points with bold headers, just the real question in your head when you open a log file: <strong>do you need to find lines, compute across fields, or edit the file in place?</strong></p>

<ul>
<li>Find lines, grep.</li>
<li>Compute or reshape data, awk.</li>
<li>Change the file, sed.</li>
</ul>

<p>Most real admin tasks are one of these, cleanly, and the rare ones that feel like two at once (find matching lines <em>and</em> count them) are just awk wearing grep's job for a minute, since awk can filter with a pattern before its action block just fine.</p>

<p>You'll still combine grep and awk plenty, and that's fine. grep filters the lines first, so awk only has to work through what's left, which matters on a big file. The real skill isn't picking a favorite tool; it's noticing what you're actually asking for: a field, a total, a changed line. Once you can name that, the right tool is obvious. Most tutorials never make you ask a real question, so you never get the practice.</p>
]]>
        </description>
    </item>
   </channel>
</rss>
