<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jean-Luc Martel</title>
    <description>The latest articles on DEV Community by Jean-Luc Martel (@jlmartel).</description>
    <link>https://dev.to/jlmartel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4061410%2Fc407a2f0-c9db-4796-bcf2-43f744536ee6.jpg</url>
      <title>DEV Community: Jean-Luc Martel</title>
      <link>https://dev.to/jlmartel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jlmartel"/>
    <language>en</language>
    <item>
      <title>How to Let gzip Find the Signal in a Pile of Documents</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Mon, 03 Aug 2026 23:19:53 +0000</pubDate>
      <link>https://dev.to/jlmartel/how-to-let-gzip-find-the-signal-in-a-pile-of-documents-2o9g</link>
      <guid>https://dev.to/jlmartel/how-to-let-gzip-find-the-signal-in-a-pile-of-documents-2o9g</guid>
      <description>&lt;p&gt;Suppose you have a directory full of text documents.&lt;/p&gt;

&lt;p&gt;Most are repetitive, padded with boilerplate, or otherwise low-signal. A few contain the useful material. You could read every file manually, feed them all into an embedding pipeline, or ask an LLM to rank them.&lt;/p&gt;

&lt;p&gt;Or you could ask &lt;strong&gt;gzip&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The basic idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repetitive text compresses well. Varied text usually does not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That makes compression ratio a crude but surprisingly useful proxy for redundancy.&lt;/p&gt;

&lt;p&gt;It will not tell you which document is &lt;em&gt;best&lt;/em&gt;. But it can help you identify which documents contain less repetition and deserve a closer look.&lt;/p&gt;

&lt;h2&gt;
  
  
  The heuristic
&lt;/h2&gt;

&lt;p&gt;For each document:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Measure its original size.&lt;/li&gt;
&lt;li&gt;Compress it individually with &lt;code&gt;gzip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Measure the compressed size.&lt;/li&gt;
&lt;li&gt;Calculate:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compressed size / original size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lower ratio means the document compressed well, which usually indicates more repetition.&lt;/p&gt;

&lt;p&gt;A higher ratio means the document was harder to compress, which may indicate more varied or information-dense content.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lower ratio: more redundant&lt;/li&gt;
&lt;li&gt;higher ratio: less redundant&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bash command
&lt;/h2&gt;

&lt;p&gt;Here is a small Bash pipeline that ranks &lt;code&gt;.txt&lt;/code&gt; files by compression ratio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ./documents &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.txt'&lt;/span&gt; &lt;span class="nt"&gt;-print0&lt;/span&gt; |
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; file&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;compressed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;gz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$compressed&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'
    raw &amp;gt; 0 {
      printf "%.3f\t%8d\t%8d\t%s\n", gz/raw, raw, gz, file
    }
  '&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-nr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.642      18432      11834  ./documents/research-notes.txt
0.417      30211      12600  ./documents/project-summary.txt
0.091      27102       2467  ./documents/standard-contract.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The columns are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ratio    original bytes    compressed bytes    filename
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the output is sorted in descending order, the least compressible files appear first.&lt;/p&gt;

&lt;p&gt;Those are the files I would inspect first when looking for the possible “gems.”&lt;/p&gt;

&lt;p&gt;To find the most repetitive documents instead, reverse the sort:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why &lt;code&gt;gzip -n&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;-n&lt;/code&gt; flag prevents &lt;code&gt;gzip&lt;/code&gt; from storing the original filename and timestamp in its output.&lt;/p&gt;

&lt;p&gt;That makes the compressed sizes more comparable across files and across runs.&lt;/p&gt;

&lt;p&gt;Without it, a small amount of unrelated metadata can leak into the measurement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is actually measuring
&lt;/h2&gt;

&lt;p&gt;This technique does not measure truth, relevance, writing quality, or semantic importance.&lt;/p&gt;

&lt;p&gt;It measures compressibility.&lt;/p&gt;

&lt;p&gt;Those things sometimes correlate, but they are not the same.&lt;/p&gt;

&lt;p&gt;A document full of repeated boilerplate will usually compress extremely well. A document with more distinct vocabulary, sentence structure, numbers, and ideas may compress less efficiently.&lt;/p&gt;

&lt;p&gt;That makes the ratio useful as a first-pass ranking signal.&lt;/p&gt;

&lt;p&gt;It is closer to a metal detector than a treasure map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important caveats
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Small files produce noisy ratios
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;gzip&lt;/code&gt; adds headers and other fixed overhead. For tiny files, that overhead can dominate the result.&lt;/p&gt;

&lt;p&gt;You may want to ignore documents below a minimum size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ./documents &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.txt'&lt;/span&gt; &lt;span class="nt"&gt;-size&lt;/span&gt; +1k &lt;span class="nt"&gt;-print0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Already-compressed formats will mislead you
&lt;/h3&gt;

&lt;p&gt;Running this directly against PDF, DOCX, ZIP, JPG, or other compressed formats mostly measures the compression characteristics of the container format.&lt;/p&gt;

&lt;p&gt;Extract the text first.&lt;/p&gt;

&lt;p&gt;For example, with PDFs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pdftotext input.pdf output.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Incompressible does not mean valuable
&lt;/h3&gt;

&lt;p&gt;Encrypted data, random identifiers, hashes, minified code, and corrupted text are all difficult to compress.&lt;/p&gt;

&lt;p&gt;They may score highly while containing little useful information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repetition is not always fluff
&lt;/h3&gt;

&lt;p&gt;Contracts, API documentation, technical specifications, and scientific papers may repeat terminology because precision requires it.&lt;/p&gt;

&lt;p&gt;A lower ratio can indicate redundancy, but it can also indicate consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Language and formatting matter
&lt;/h3&gt;

&lt;p&gt;Compression ratios can be affected by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document length&lt;/li&gt;
&lt;li&gt;whitespace&lt;/li&gt;
&lt;li&gt;markup&lt;/li&gt;
&lt;li&gt;tables&lt;/li&gt;
&lt;li&gt;repeated headings&lt;/li&gt;
&lt;li&gt;source language&lt;/li&gt;
&lt;li&gt;character encoding&lt;/li&gt;
&lt;li&gt;templated metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a fairer comparison, normalize the documents first.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'[:space:]'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &amp;lt; input.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could also strip HTML, remove headers and footers, or convert everything to lowercase before compression.&lt;/p&gt;

&lt;p&gt;Just remember that normalization changes what you are measuring.&lt;/p&gt;

&lt;h2&gt;
  
  
  A slightly more useful version
&lt;/h2&gt;

&lt;p&gt;For larger collections, I would filter out tiny files and print the percentage saved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ./documents &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.txt'&lt;/span&gt; &lt;span class="nt"&gt;-size&lt;/span&gt; +1k &lt;span class="nt"&gt;-print0&lt;/span&gt; |
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; file&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;compressed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;gz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$compressed&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'
    raw &amp;gt; 0 {
      ratio = gz / raw
      saved = 100 * (1 - ratio)

      printf "%6.2f%% saved\t%8d bytes\t%s\n",
             saved, raw, file
    }
  '&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sorts the files with the lowest percentage saved first, meaning the least compressible documents rise to the top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this could be useful
&lt;/h2&gt;

&lt;p&gt;This trick can be handy for quickly triaging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scraped web pages&lt;/li&gt;
&lt;li&gt;exported support tickets&lt;/li&gt;
&lt;li&gt;meeting transcripts&lt;/li&gt;
&lt;li&gt;research notes&lt;/li&gt;
&lt;li&gt;log samples&lt;/li&gt;
&lt;li&gt;generated reports&lt;/li&gt;
&lt;li&gt;document archives&lt;/li&gt;
&lt;li&gt;large sets of Markdown files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is especially useful when you want a fast local heuristic without setting up a database, embedding model, or external API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compression as a feature
&lt;/h2&gt;

&lt;p&gt;The broader idea is more interesting than the Bash command.&lt;/p&gt;

&lt;p&gt;Compression ratio can be treated as a lightweight feature in a ranking system.&lt;/p&gt;

&lt;p&gt;You could combine it with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document length&lt;/li&gt;
&lt;li&gt;vocabulary diversity&lt;/li&gt;
&lt;li&gt;duplicate paragraph counts&lt;/li&gt;
&lt;li&gt;keyword density&lt;/li&gt;
&lt;li&gt;entropy&lt;/li&gt;
&lt;li&gt;embedding similarity&lt;/li&gt;
&lt;li&gt;recency&lt;/li&gt;
&lt;li&gt;source reputation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compression alone is crude.&lt;/p&gt;

&lt;p&gt;Compression plus a few other signals could become a genuinely useful document-triage tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;There are sophisticated ways to rank a pile of documents.&lt;/p&gt;

&lt;p&gt;Sometimes, though, a 40-year-old compression algorithm is enough to tell you which files keep repeating themselves.&lt;/p&gt;

&lt;p&gt;And that is often a very good place to start.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>automation</category>
      <category>bash</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
