<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>cli · wleeaf field notes</title><link>https://articles.wleeaf.dev/tags/cli/</link><description>Hands-on guides and build logs from the wleeaf studio: self-hosting, Linux, networking, Docker, the command line and reverse engineering.</description><language>en-us</language><lastBuildDate>Sat, 04 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://articles.wleeaf.dev/tags/cli/feed.xml" rel="self" type="application/rss+xml"/><item><title>awk in 10 Minutes With Practical Examples</title><link>https://articles.wleeaf.dev/posts/awk-practical-examples/</link><pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate><guid>https://articles.wleeaf.dev/posts/awk-practical-examples/</guid><description>Nobody reads the awk manual. Here are the patterns that cover 90% of real-world use.</description><category>awk</category><category>cli</category><category>linux</category><content:encoded><![CDATA[<p>awk is one of those tools that looks intimidating until you learn five patterns. Then you use it every day. I am not going to explain the full language. Here are the patterns that actually matter.</p>
<h2 id="pattern-1-print-a-column">Pattern 1: Print a Column<a class="anchor" href="#pattern-1-print-a-column" aria-label="Link to “Pattern 1: Print a Column”">#</a></h2>
<p>awk splits each line into fields. <code>$1</code> is the first, <code>$2</code> is the second, <code>$0</code> is the whole line:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Print the first column of ps output</span>
</span></span><span class="line"><span class="cl">ps aux <span class="p">|</span> awk <span class="s1">&#39;{print $1}&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Print columns 1 and 11 (user and command)</span>
</span></span><span class="line"><span class="cl">ps aux <span class="p">|</span> awk <span class="s1">&#39;{print $1, $11}&#39;</span></span></span></code></pre></div>
</div>
<p>The default field separator is whitespace. Change it with <code>-F</code>:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Parse /etc/passwd (colon-separated)</span>
</span></span><span class="line"><span class="cl">awk -F: <span class="s1">&#39;{print $1, $7}&#39;</span> /etc/passwd
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Parse CSV</span>
</span></span><span class="line"><span class="cl">awk -F, <span class="s1">&#39;{print $2}&#39;</span> data.csv</span></span></code></pre></div>
</div>
<h2 id="pattern-2-filter-rows">Pattern 2: Filter Rows<a class="anchor" href="#pattern-2-filter-rows" aria-label="Link to “Pattern 2: Filter Rows”">#</a></h2>
<p>Put a condition before the action:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Lines where column 3 is greater than 100</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;$3 &gt; 100&#39;</span> data.txt
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Lines containing &#34;ERROR&#34;</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;/ERROR/&#39;</span> app.log
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Lines where the first field matches a pattern</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;$1 ~ /^192\.168/&#39;</span> access.log</span></span></code></pre></div>
</div>
<p>Combine conditions:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Memory usage over 50% AND the process is not root</span>
</span></span><span class="line"><span class="cl">ps aux <span class="p">|</span> awk <span class="s1">&#39;$4 &gt; 50.0 &amp;&amp; $1 != &#34;root&#34; {print $1, $4, $11}&#39;</span></span></span></code></pre></div>
</div>
<h2 id="pattern-3-sum-a-column">Pattern 3: Sum a Column<a class="anchor" href="#pattern-3-sum-a-column" aria-label="Link to “Pattern 3: Sum a Column”">#</a></h2>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Total bytes transferred (column 10 in access logs)</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;{sum += $10} END {print sum}&#39;</span> access.log
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Average response time</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;{sum += $NF; n++} END {print sum/n}&#39;</span> response_times.log</span></span></code></pre></div>
</div>
<p><code>END</code> runs after all lines are processed. <code>NF</code> is the number of fields on the current line, so <code>$NF</code> is the last field.</p>
<h2 id="pattern-4-count-and-group">Pattern 4: Count and Group<a class="anchor" href="#pattern-4-count-and-group" aria-label="Link to “Pattern 4: Count and Group”">#</a></h2>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Count HTTP status codes</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;{count[$9]++} END {for (c in count) print c, count[c]}&#39;</span> access.log <span class="p">|</span> sort -rn -k2
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Output:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 200 45231</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 304 12044</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 404 891</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 500 23</span></span></span></code></pre></div>
</div>
<p>This uses an associative array. <code>count[$9]++</code> increments the count for each unique value in column 9.</p>
<p>Top 10 IP addresses by request count:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk <span class="s1">&#39;{count[$1]++} END {for (ip in count) print count[ip], ip}&#39;</span> access.log <span class="p">|</span> sort -rn <span class="p">|</span> head -10</span></span></code></pre></div>
</div>
<h2 id="pattern-5-transform-fields">Pattern 5: Transform Fields<a class="anchor" href="#pattern-5-transform-fields" aria-label="Link to “Pattern 5: Transform Fields”">#</a></h2>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Convert bytes to megabytes</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;{printf &#34;%s %.1fMB\n&#34;, $1, $2/1048576}&#39;</span> sizes.txt
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Add a prefix to every line</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;{print &#34;[INFO]&#34;, $0}&#39;</span> app.log
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Swap two columns</span>
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;{temp=$1; $1=$2; $2=temp; print}&#39;</span> data.txt</span></span></code></pre></div>
</div>
<h2 id="real-world-examples">Real-World Examples<a class="anchor" href="#real-world-examples" aria-label="Link to “Real-World Examples”">#</a></h2>
<h3 id="parse-docker-ps-output">Parse Docker ps output<a class="anchor" href="#parse-docker-ps-output" aria-label="Link to “Parse Docker ps output”">#</a></h3>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker ps --format <span class="s1">&#39;{{.Names}}\t{{.Status}}\t{{.Ports}}&#39;</span> <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  awk -F<span class="s1">&#39;\t&#39;</span> <span class="s1">&#39;{printf &#34;%-20s %-15s %s\n&#34;, $1, $2, $3}&#39;</span></span></span></code></pre></div>
</div>
<h3 id="find-the-largest-docker-images">Find the largest Docker images<a class="anchor" href="#find-the-largest-docker-images" aria-label="Link to “Find the largest Docker images”">#</a></h3>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker images --format <span class="s1">&#39;{{.Repository}}:{{.Tag}}\t{{.Size}}&#39;</span> <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  awk -F<span class="s1">&#39;\t&#39;</span> <span class="s1">&#39;{
</span></span></span><span class="line"><span class="cl"><span class="s1">    size = $2
</span></span></span><span class="line"><span class="cl"><span class="s1">    if (size ~ /GB/) {
</span></span></span><span class="line"><span class="cl"><span class="s1">      gsub(/GB/, &#34;&#34;, size)
</span></span></span><span class="line"><span class="cl"><span class="s1">      mb = size * 1024
</span></span></span><span class="line"><span class="cl"><span class="s1">    } else if (size ~ /MB/) {
</span></span></span><span class="line"><span class="cl"><span class="s1">      gsub(/MB/, &#34;&#34;, size)
</span></span></span><span class="line"><span class="cl"><span class="s1">      mb = size
</span></span></span><span class="line"><span class="cl"><span class="s1">    } else {
</span></span></span><span class="line"><span class="cl"><span class="s1">      mb = 0
</span></span></span><span class="line"><span class="cl"><span class="s1">    }
</span></span></span><span class="line"><span class="cl"><span class="s1">    printf &#34;%8.0fMB  %s\n&#34;, mb, $1
</span></span></span><span class="line"><span class="cl"><span class="s1">  }&#39;</span> <span class="p">|</span> sort -rn <span class="p">|</span> head -10</span></span></code></pre></div>
</div>
<h3 id="calculate-uptime-percentage">Calculate uptime percentage<a class="anchor" href="#calculate-uptime-percentage" aria-label="Link to “Calculate uptime percentage”">#</a></h3>
<p>Given a log with timestamps and status:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk <span class="s1">&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">  /UP/   { up++ }
</span></span></span><span class="line"><span class="cl"><span class="s1">  /DOWN/ { down++ }
</span></span></span><span class="line"><span class="cl"><span class="s1">  END {
</span></span></span><span class="line"><span class="cl"><span class="s1">    total = up + down
</span></span></span><span class="line"><span class="cl"><span class="s1">    if (total &gt; 0)
</span></span></span><span class="line"><span class="cl"><span class="s1">      printf &#34;Uptime: %.2f%% (%d/%d checks)\n&#34;, (up/total)*100, up, total
</span></span></span><span class="line"><span class="cl"><span class="s1">  }
</span></span></span><span class="line"><span class="cl"><span class="s1">&#39;</span> monitoring.log</span></span></code></pre></div>
</div>
<h3 id="extract-unique-error-messages">Extract unique error messages<a class="anchor" href="#extract-unique-error-messages" aria-label="Link to “Extract unique error messages”">#</a></h3>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk <span class="s1">&#39;/ERROR/ {
</span></span></span><span class="line"><span class="cl"><span class="s1">  msg = &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s1">  for (i=4; i&lt;=NF; i++) msg = msg &#34; &#34; $i
</span></span></span><span class="line"><span class="cl"><span class="s1">  errors[msg]++
</span></span></span><span class="line"><span class="cl"><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">END {
</span></span></span><span class="line"><span class="cl"><span class="s1">  for (e in errors) printf &#34;%5d %s\n&#34;, errors[e], e
</span></span></span><span class="line"><span class="cl"><span class="s1">}&#39;</span> app.log <span class="p">|</span> sort -rn <span class="p">|</span> head -20</span></span></code></pre></div>
</div>
<h2 id="built-in-variables">Built-in Variables<a class="anchor" href="#built-in-variables" aria-label="Link to “Built-in Variables”">#</a></h2>
<table>
  <thead>
      <tr>
          <th>Variable</th>
          <th>Meaning</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>NR</code></td>
          <td>Current line number</td>
      </tr>
      <tr>
          <td><code>NF</code></td>
          <td>Number of fields on current line</td>
      </tr>
      <tr>
          <td><code>FS</code></td>
          <td>Field separator</td>
      </tr>
      <tr>
          <td><code>OFS</code></td>
          <td>Output field separator</td>
      </tr>
      <tr>
          <td><code>$0</code></td>
          <td>Entire line</td>
      </tr>
      <tr>
          <td><code>$1..$n</code></td>
          <td>Individual fields</td>
      </tr>
      <tr>
          <td><code>FILENAME</code></td>
          <td>Current filename</td>
      </tr>
  </tbody>
</table>
<h2 id="when-to-use-awk-vs-other-tools">When to Use awk vs. Other Tools<a class="anchor" href="#when-to-use-awk-vs-other-tools" aria-label="Link to “When to Use awk vs. Other Tools”">#</a></h2>
<ul>
<li><strong>cut</strong>: When you just need a column and nothing else. <code>cut -d: -f1 /etc/passwd</code> is simpler than awk for trivial extraction.</li>
<li><strong>grep</strong>: When you just need to filter lines by a pattern.</li>
<li><strong>sed</strong>: When you need to do find-and-replace on text.</li>
<li><strong>awk</strong>: When you need to do math, grouping, conditional logic, or work with multiple fields at once.</li>
</ul>
<p>The mental model is simple. awk reads lines, splits them into fields, and lets you write rules about what to do with each line. Once that clicks, you start seeing awk solutions everywhere.</p>
]]></content:encoded></item><item><title>jq Is the SQL of JSON</title><link>https://articles.wleeaf.dev/posts/jq-command-line-json/</link><pubDate>Fri, 27 Mar 2026 00:00:00 +0000</pubDate><guid>https://articles.wleeaf.dev/posts/jq-command-line-json/</guid><description>Every API returns JSON now. jq turns your terminal into a query engine for it.</description><category>cli</category><category>json</category><category>linux</category><content:encoded><![CDATA[<p>Every API you talk to returns JSON. Every config file is JSON. Every log pipeline emits JSON. And yet most people still pipe <code>curl</code> output through <code>grep</code> and pray.</p>
<p>jq is the tool that makes JSON usable from the command line. Once you learn the basics, you will never go back.</p>
<h2 id="basics">Basics<a class="anchor" href="#basics" aria-label="Link to “Basics”">#</a></h2>
<p>Pretty-print some JSON:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -s https://api.github.com/users/torvalds <span class="p">|</span> jq .</span></span></code></pre></div>
</div>
<p>Extract a single field:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;{&#34;name&#34;: &#34;Linus&#34;, &#34;repos&#34;: 5}&#39;</span> <span class="p">|</span> jq .name
</span></span><span class="line"><span class="cl"><span class="c1"># &#34;Linus&#34;</span></span></span></code></pre></div>
</div>
<p>Drop the quotes with <code>-r</code>:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;{&#34;name&#34;: &#34;Linus&#34;}&#39;</span> <span class="p">|</span> jq -r .name
</span></span><span class="line"><span class="cl"><span class="c1"># Linus</span></span></span></code></pre></div>
</div>
<h2 id="arrays">Arrays<a class="anchor" href="#arrays" aria-label="Link to “Arrays”">#</a></h2>
<p>Get the first element:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;[1, 2, 3]&#39;</span> <span class="p">|</span> jq <span class="s1">&#39;.[0]&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 1</span></span></span></code></pre></div>
</div>
<p>Iterate over all elements:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;[{&#34;name&#34;: &#34;a&#34;}, {&#34;name&#34;: &#34;b&#34;}]&#39;</span> <span class="p">|</span> jq <span class="s1">&#39;.[].name&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &#34;a&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &#34;b&#34;</span></span></span></code></pre></div>
</div>
<h2 id="filtering">Filtering<a class="anchor" href="#filtering" aria-label="Link to “Filtering”">#</a></h2>
<p>This is where it gets powerful. Say you have a list of GitHub repos:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -s https://api.github.com/users/torvalds/repos <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  jq <span class="s1">&#39;[.[] | select(.stargazers_count &gt; 1000)] | length&#39;</span></span></span></code></pre></div>
</div>
<p>That filters repos with more than 1000 stars and counts them.</p>
<h2 id="constructing-objects">Constructing Objects<a class="anchor" href="#constructing-objects" aria-label="Link to “Constructing Objects”">#</a></h2>
<p>You can reshape JSON on the fly:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -s https://api.github.com/users/torvalds/repos <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  jq <span class="s1">&#39;.[] | {name: .name, stars: .stargazers_count, lang: .language}&#39;</span></span></span></code></pre></div>
</div>
<p>This outputs a new object for each repo with only the fields you care about.</p>
<h2 id="real-world-parsing-docker">Real World: Parsing Docker<a class="anchor" href="#real-world-parsing-docker" aria-label="Link to “Real World: Parsing Docker”">#</a></h2>
<p>List container names and their memory usage:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker stats --no-stream --format <span class="s1">&#39;{{json .}}&#39;</span> <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  jq -r <span class="s1">&#39;[.Name, .MemUsage] | @tsv&#39;</span></span></span></code></pre></div>
</div>
<p>Find containers using more than 100MB:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker stats --no-stream --format <span class="s1">&#39;{{json .}}&#39;</span> <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  jq -r <span class="s1">&#39;select(.MemPerc | gsub(&#34;%&#34;; &#34;&#34;) | tonumber &gt; 1) | .Name&#39;</span></span></span></code></pre></div>
</div>
<h2 id="working-with-nested-data">Working With Nested Data<a class="anchor" href="#working-with-nested-data" aria-label="Link to “Working With Nested Data”">#</a></h2>
<p>Given deeply nested JSON:</p>
<div class="code">
<div class="code-head"><span class="code-lang">json</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;users&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nt">&#34;profile&#34;</span><span class="p">:</span> <span class="p">{</span><span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a@b.com&#34;</span><span class="p">}},</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nt">&#34;profile&#34;</span><span class="p">:</span> <span class="p">{</span><span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;c@d.com&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
</div>
<p>Extract all emails:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">jq <span class="s1">&#39;[.data.users[].profile.email]&#39;</span> data.json
</span></span><span class="line"><span class="cl"><span class="c1"># [&#34;a@b.com&#34;, &#34;c@d.com&#34;]</span></span></span></code></pre></div>
</div>
<h2 id="combining-with-other-tools">Combining With Other Tools<a class="anchor" href="#combining-with-other-tools" aria-label="Link to “Combining With Other Tools”">#</a></h2>
<p>jq plays well with the rest of the Unix toolkit:</p>
<div class="code">
<div class="code-head"><span class="code-lang">bash</span><button type="button" class="code-copy" data-copy-code hidden><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2.5"/><path d="M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8"/></svg><span>Copy</span></button></div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Get all unique languages across repos</span>
</span></span><span class="line"><span class="cl">curl -s https://api.github.com/users/torvalds/repos <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  jq -r <span class="s1">&#39;.[].language // empty&#39;</span> <span class="p">|</span> sort -u
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Convert JSON array to lines for xargs</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;[&#34;file1.txt&#34;, &#34;file2.txt&#34;]&#39;</span> <span class="p">|</span> jq -r <span class="s1">&#39;.[]&#39;</span> <span class="p">|</span> xargs rm
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Merge multiple JSON files</span>
</span></span><span class="line"><span class="cl">jq -s <span class="s1">&#39;add&#39;</span> file1.json file2.json &gt; merged.json</span></span></code></pre></div>
</div>
<h2 id="the-cheat-sheet">The Cheat Sheet<a class="anchor" href="#the-cheat-sheet" aria-label="Link to “The Cheat Sheet”">#</a></h2>
<table>
  <thead>
      <tr>
          <th>Pattern</th>
          <th>What it does</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>.field</code></td>
          <td>Get field</td>
      </tr>
      <tr>
          <td><code>.[]</code></td>
          <td>Iterate array</td>
      </tr>
      <tr>
          <td><code>select(cond)</code></td>
          <td>Filter</td>
      </tr>
      <tr>
          <td><code>map(expr)</code></td>
          <td>Transform array</td>
      </tr>
      <tr>
          <td><code>length</code></td>
          <td>Count</td>
      </tr>
      <tr>
          <td><code>keys</code></td>
          <td>Object keys</td>
      </tr>
      <tr>
          <td><code>to_entries</code></td>
          <td>Object to key-value pairs</td>
      </tr>
      <tr>
          <td><code>@csv</code></td>
          <td>Output as CSV</td>
      </tr>
      <tr>
          <td><code>@tsv</code></td>
          <td>Output as TSV</td>
      </tr>
      <tr>
          <td><code>//</code></td>
          <td>Default value</td>
      </tr>
  </tbody>
</table>
<p>jq has a learning curve, but it is one of those tools where the investment pays off within a week. Every time you find yourself writing a Python script just to parse some JSON, remember that jq probably does it in one line.</p>
]]></content:encoded></item></channel></rss>