<?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>MacOS on Nelson Figueroa</title><link>https://nelson.cloud/categories/macos/</link><description>Recent content in MacOS on Nelson Figueroa</description><image><title>Nelson Figueroa</title><url>https://nelson.cloud/apple-touch-icon.png</url><link>https://nelson.cloud/categories/macos/</link></image><language>en</language><lastBuildDate>Sun, 09 Aug 2026 01:22:57 -0700</lastBuildDate><atom:link href="https://nelson.cloud/categories/macos/index.xml" rel="self" type="application/rss+xml"/><item><title>Setting Up a Time Machine Drive from the Command Line</title><link>https://nelson.cloud/setting-up-a-time-machine-drive-from-the-command-line/?ref=rss</link><pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate><guid>https://nelson.cloud/setting-up-a-time-machine-drive-from-the-command-line/?ref=rss</guid><description>Steps to set up a Time Machine drive from the command line.</description><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>It&rsquo;s possible to set up Time Machine drives from the command line. This is way more convenient and becomes scriptable (there&rsquo;s one GUI checkbox at the end if you encrypt, so the drive can unlock itself). Also, based on my own personal experience, the Time Machine GUI can be unresponsive so the CLI is much better.</p>
<p>I&rsquo;ll be using a 1TB external SSD in this guide.</p>
<p>Here&rsquo;s how you set up a drive.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Some of these terminal commands require Full Disk Access. Specifically, the <code>tmutil</code> commands we&rsquo;ll be using later on.</p>
<p>Grant your preferred terminal app full disk access in System Settings -&gt; Privacy &amp; Security -&gt; Full Disk Access.</p>
<h2 id="identifying-the-drive">Identifying the Drive</h2>
<p>Plug in your drive. Unlock it if you have to.</p>
<p>Run the following to get some information we&rsquo;ll need.</p>
<p>Here is what you&rsquo;ll see if the drive is currently being used for Time Machine:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil list external
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">/dev/disk4 (external, physical):
</span></span></span><span class="line"><span class="cl"><span class="go">   #:                       TYPE NAME                    SIZE       IDENTIFIER
</span></span></span><span class="line"><span class="cl"><span class="go">   0:      GUID_partition_scheme                        *1.0 TB     disk4
</span></span></span><span class="line"><span class="cl"><span class="go">   1:                        EFI EFI                     209.7 MB   disk4s1
</span></span></span><span class="line"><span class="cl"><span class="go">   2:                 Apple_APFS Container disk5         1000.0 GB  disk4s2
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">/dev/disk5 (synthesized):
</span></span></span><span class="line"><span class="cl"><span class="go">   #:                       TYPE NAME                    SIZE       IDENTIFIER
</span></span></span><span class="line"><span class="cl"><span class="go">   0:      APFS Container Scheme -                      +1000.0 GB  disk5
</span></span></span><span class="line"><span class="cl"><span class="go">                                 Physical Store disk4s2
</span></span></span><span class="line"><span class="cl"><span class="go">   1:                APFS Volume backup                  768.2 GB   disk5s1
</span></span></span></code></pre></div><p>Here is what you&rsquo;ll see if the drive is brand new:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil list external
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">/dev/disk4 (external, physical):
</span></span></span><span class="line"><span class="cl"><span class="go">   #:                       TYPE NAME                    SIZE       IDENTIFIER
</span></span></span><span class="line"><span class="cl"><span class="go">   0:     FDisk_partition_scheme                        *1.0 TB     disk4
</span></span></span><span class="line"><span class="cl"><span class="go">   1:               Windows_NTFS Untitled                1.0 TB     disk4s1
</span></span></span></code></pre></div><p>Two identifiers matter here:</p>
<ul>
<li><strong><code>disk4</code></strong> — the whole physical disk. We&rsquo;ll need this later on when running the <code>eraseDisk</code> command.</li>
<li><strong><code>disk5</code></strong> — the APFS container. This is what we&rsquo;ll need for the <code>addVolume</code> command. (A brand new drive won&rsquo;t have this one yet. It&rsquo;ll get created when we erase the disk in a later step.)</li>
</ul>
<blockquote><p><strong>Warning:</strong></p><code>eraseDisk</code> destroys everything on whichever disk you name. Confirm you&rsquo;ve got the right one before running it or you might nuke your local drive instead of your backup drive.</blockquote>

<p>Confirm that you have the correct disk with this command.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil info disk4 <span class="p">|</span> grep -iE <span class="s2">&#34;device location|protocol|disk size&#34;</span>
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Protocol:                  USB
</span></span></span><span class="line"><span class="cl"><span class="go">Disk Size:                 1.0 TB (1000204140544 Bytes) (exactly 1953523712 512-Byte-Units)
</span></span></span><span class="line"><span class="cl"><span class="go">Device Location:           External
</span></span></span></code></pre></div><p>We know this one is the external drive due to the <code>Device Location: External</code> line. On Apple silicon the internal drive shows <code>Protocol: Apple Fabric</code> and <code>Device Location: Internal</code>.</p>
<h2 id="erasing-the-disk">Erasing the Disk</h2>
<p>We&rsquo;ll need to erase the disk next. The steps vary slightly depending on whether the drive is brand new or is an existing Time Machine drive.</p>
<h3 id="erasing-a-brand-new-drive">Erasing a Brand New Drive</h3>
<p>New drives usually ship as ExFAT with an MBR partition scheme, so there&rsquo;s no APFS container yet. We can erase and convert the disk with this command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil eraseDisk APFS backup GPT disk4
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Started erase on disk4
</span></span></span><span class="line"><span class="cl"><span class="go">Unmounting disk
</span></span></span><span class="line"><span class="cl"><span class="go">Creating the partition map
</span></span></span><span class="line"><span class="cl"><span class="go">Waiting for partitions to activate
</span></span></span><span class="line"><span class="cl"><span class="go">Formatting disk4s2 as APFS with name backup
</span></span></span><span class="line"><span class="cl"><span class="go">Mounting disk
</span></span></span><span class="line"><span class="cl"><span class="go">Finished erase on disk4
</span></span></span></code></pre></div><p>This results in a drive with a GPT scheme, an EFI partition, and an APFS container with one volume in it (read more on containers vs volumes in 

<a href="https://eclecticlight.co/2024/04/02/apfs-containers-and-volumes/" target="_blank" rel="noopener">APFS: Containers and Volumes</a>). It does not encrypt the volume, enable ownership, or set the Time Machine role, which are all things we need. So we&rsquo;ll delete this newly created volume and create a proper one later.</p>
<p>Run this again to figure out the identifier:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil list external
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">/dev/disk4 (external, physical):
</span></span></span><span class="line"><span class="cl"><span class="go">   #:                       TYPE NAME                    SIZE       IDENTIFIER
</span></span></span><span class="line"><span class="cl"><span class="go">   0:      GUID_partition_scheme                        *1.0 TB     disk4
</span></span></span><span class="line"><span class="cl"><span class="go">   1:                        EFI EFI                     209.7 MB   disk4s1
</span></span></span><span class="line"><span class="cl"><span class="go">   2:                 Apple_APFS Container disk5         1000.0 GB  disk4s2
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">/dev/disk5 (synthesized):
</span></span></span><span class="line"><span class="cl"><span class="go">   #:                       TYPE NAME                    SIZE       IDENTIFIER
</span></span></span><span class="line"><span class="cl"><span class="go">   0:      APFS Container Scheme -                      +1000.0 GB  disk5
</span></span></span><span class="line"><span class="cl"><span class="go">                                 Physical Store disk4s2
</span></span></span><span class="line"><span class="cl"><span class="go">   1:                APFS Volume backup                  806.9 KB   disk5s1
</span></span></span></code></pre></div><p>The identifier is <code>disk5s1</code> in this case.</p>
<p>Now use that identifier to delete the volume that was created in the <code>eraseDisk</code> step:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil apfs deleteVolume disk5s1
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Started APFS operation
</span></span></span><span class="line"><span class="cl"><span class="go">Deleting APFS Volume from its APFS Container
</span></span></span><span class="line"><span class="cl"><span class="go">Unmounting disk5s1
</span></span></span><span class="line"><span class="cl"><span class="go">Erasing any xART session referenced by 40D7443F-46DA-4DA5-9F61-41AEEBEAA1CF
</span></span></span><span class="line"><span class="cl"><span class="go">Deleting Volume
</span></span></span><span class="line"><span class="cl"><span class="go">Removing any Preboot and Recovery Directories
</span></span></span><span class="line"><span class="cl"><span class="go">Finished APFS operation
</span></span></span></code></pre></div><p>That&rsquo;s it for this section. Skip ahead to the &ldquo;Creating a Volume&rdquo; section.</p>
<h3 id="erasing-a-drive-already-used-for-time-machine">Erasing a Drive Already Used for Time Machine</h3>
<p>If the drive is already being used for Time Machine we need to remove the destination (the disk entry in the Time Machine GUI).</p>
<p>First, figure out the destination UUID:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil destinationinfo
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">====================================================
</span></span></span><span class="line"><span class="cl"><span class="go">Name          : backup
</span></span></span><span class="line"><span class="cl"><span class="go">Kind          : Local
</span></span></span><span class="line"><span class="cl"><span class="go">Mount Point   : /Volumes/backup
</span></span></span><span class="line"><span class="cl"><span class="go">ID            : E10FD749-891E-4051-9135-3457E80F90E7
</span></span></span></code></pre></div><p>Then remove the old destination. We&rsquo;re using <code>sudo</code> so it&rsquo;ll prompt you for your machine&rsquo;s password.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo tmutil removedestination E10FD749-891E-4051-9135-3457E80F90E7
</span></span></code></pre></div><p>Verify it&rsquo;s gone:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil destinationinfo
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">tmutil: No destinations configured.
</span></span></span></code></pre></div><p>You can double check that this worked by checking in System Settings -&gt; General -&gt; Time Machine. There should be no backup drive listed. If it&rsquo;s still there, you can manually remove it in the GUI.</p>
<p>Now delete the old volume. The container stays, so there&rsquo;s no need to repartition the whole disk:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil apfs deleteVolume disk5s1
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Started APFS operation
</span></span></span><span class="line"><span class="cl"><span class="go">Deleting APFS Volume from its APFS Container
</span></span></span><span class="line"><span class="cl"><span class="go">Unmounting disk5s1
</span></span></span><span class="line"><span class="cl"><span class="go">Erasing any xART session referenced by 016C2F32-854B-4B94-8B87-DEA1774902CB
</span></span></span><span class="line"><span class="cl"><span class="go">Deleting Volume
</span></span></span><span class="line"><span class="cl"><span class="go">Removing any Preboot and Recovery Directories
</span></span></span><span class="line"><span class="cl"><span class="go">Finished APFS operation
</span></span></span></code></pre></div><blockquote><p><strong>Warning:</strong></p><p>If you get an error like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">The volume on disk4 couldn&#39;t be unmounted because it is in use by process 48552 (mdwrite)
</span></span><span class="line"><span class="cl">Error: -69877: Couldn&#39;t open device</span></span></code></pre></div><p>That&rsquo;s Spotlight. Removing the Time Machine destination makes macOS stop treating the drive as a backup target, so Spotlight starts indexing it like any other volume and holds it open.</p>
<p>Turn indexing off for that volume and try again:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo mdutil -i off /Volumes/backup</span></span></code></pre></blockquote>

<h2 id="creating-a-volume">Creating a Volume</h2>
<p>Now that the external drive has been erased, we need to create an APFS volume on the drive. Decide if you want your backups to be unencrypted or encrypted and follow the corresponding steps.</p>
<p>Note that this only worked for me with the <code>-role T</code> flag in the commands. Do not leave it out! If you skip this option, macOS deletes the volume you just created and builds its own in its place when you register the drive in a later step. It has to do with APFS volume roles. The <code>T</code> role is for Time Machine backup stores. You can read more about these roles here: 

<a href="https://eclecticlight.co/2024/11/21/how-do-apfs-volume-roles-work/" target="_blank" rel="noopener">How do APFS volume roles work?</a>.</p>
<h3 id="creating-a-volume-without-encryption">Creating a Volume Without Encryption</h3>
<p>Run the following command to create a volume without encryption:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil apfs addVolume disk5 APFS backup -role T
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Will export new APFS Volume &#34;backup&#34; from APFS Container Reference disk5
</span></span></span><span class="line"><span class="cl"><span class="go">Started APFS operation on disk5
</span></span></span><span class="line"><span class="cl"><span class="go">Preparing to add APFS Volume to APFS Container disk5
</span></span></span><span class="line"><span class="cl"><span class="go">Creating APFS Volume
</span></span></span><span class="line"><span class="cl"><span class="go">Created new APFS Volume disk5s2
</span></span></span><span class="line"><span class="cl"><span class="go">Mounting APFS Volume
</span></span></span><span class="line"><span class="cl"><span class="go">Setting volume permissions
</span></span></span><span class="line"><span class="cl"><span class="go">Disk from APFS operation: disk5s2
</span></span></span><span class="line"><span class="cl"><span class="go">Finished APFS operation on disk5
</span></span></span></code></pre></div><h3 id="creating-a-volume-with-encryption">Creating a Volume With Encryption</h3>
<p>Run the following command. It&rsquo;ll prompt you for a password for your drive.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil apfs addVolume disk5 APFS backup -passprompt -role T
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Passphrase:
</span></span></span><span class="line"><span class="cl"><span class="go">Repeat passphrase:
</span></span></span><span class="line"><span class="cl"><span class="go">Will export new encrypted APFS Volume &#34;backup&#34; from APFS Container Reference disk5
</span></span></span><span class="line"><span class="cl"><span class="go">Started APFS operation on disk5
</span></span></span><span class="line"><span class="cl"><span class="go">Preparing to add APFS Volume to APFS Container disk5
</span></span></span><span class="line"><span class="cl"><span class="go">Creating APFS Volume
</span></span></span><span class="line"><span class="cl"><span class="go">Created new APFS Volume disk5s2
</span></span></span><span class="line"><span class="cl"><span class="go">Mounting APFS Volume
</span></span></span><span class="line"><span class="cl"><span class="go">Setting volume permissions
</span></span></span><span class="line"><span class="cl"><span class="go">Disk from APFS operation: disk5s2
</span></span></span><span class="line"><span class="cl"><span class="go">Finished APFS operation on disk5
</span></span></span></code></pre></div><p>Run this to confirm everything went well.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil apfs list disk5 <span class="p">|</span> grep -E <span class="s2">&#34;Volume disk|Role|Name:|FileVault&#34;</span>
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">    +-&gt; Volume disk5s2 E3EA1B15-B920-4313-AB30-01E4AF10A27D
</span></span></span><span class="line"><span class="cl"><span class="go">        APFS Volume Disk (Role):   disk5s2 (Backup)
</span></span></span><span class="line"><span class="cl"><span class="go">        Name:                      backup (Case-insensitive)
</span></span></span><span class="line"><span class="cl"><span class="go">        FileVault:                 Yes (Unlocked)
</span></span></span></code></pre></div><p>Under <code>disk5s2</code> you&rsquo;ll see <code>FileVault: Yes (Unlocked)</code> if it&rsquo;s an encrypted volume. You&rsquo;ll see <code>FileVault: No</code> if it&rsquo;s an unencrypted volume.</p>
<p>Two things to note here:</p>
<ul>
<li>The volume identifier won&rsquo;t always be <code>disk5s2</code>, APFS reuses freed slots so yours may be something like <code>disk5s1</code> or <code>disk5s3</code>.</li>
<li>Write down the volume UUID, we&rsquo;ll need it later on to verify everything works.</li>
</ul>
<h2 id="enabling-ownership">Enabling Ownership</h2>
<p>Time Machine refuses any destination that doesn&rsquo;t enforce file ownership. It can&rsquo;t preserve the UID or GID of what it backs up without file ownership. Volumes created from the command line have it turned off by default. Run the following to enable ownership, replacing the path with your own external drive&rsquo;s path:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo diskutil enableOwnership /Volumes/backup
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">File system user/group ownership enabled
</span></span></span></code></pre></div><p>Run the following to double check that it worked. <code>Owners</code> should be <code>Enabled</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil info /Volumes/backup <span class="p">|</span> grep -i owners
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">   Owners:                    Enabled
</span></span></span></code></pre></div><h2 id="registering-the-drive-in-time-machine">Registering the Drive in Time Machine</h2>
<p>&ldquo;Registering&rdquo; means telling Time Machine to use this volume as a backup destination. It&rsquo;s what the GUI&rsquo;s &ldquo;Add Backup Disk&rdquo; button does. The button and the command we&rsquo;re going to run both write to <code>/Library/Preferences/com.apple.TimeMachine.plist</code>.</p>
<p>Run the following to register your drive:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo tmutil setdestination -a /Volumes/backup
</span></span></code></pre></div><p>No output means it worked. <code>-a</code> appends to your destination list rather than replacing it.</p>
<p>If you run into this error, try waiting a bit and then try again:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">/Volumes/backup: The operation couldn&#39;t be completed. Operation not supported (error 45)
</span></span><span class="line"><span class="cl">The backup destination could not be added.</span></span></code></pre></div><p>Then run these commands to double check everything went well:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil destinationinfo
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">====================================================
</span></span></span><span class="line"><span class="cl"><span class="go">Name          : backup
</span></span></span><span class="line"><span class="cl"><span class="go">Kind          : Local
</span></span></span><span class="line"><span class="cl"><span class="go">Mount Point   : /Volumes/backup
</span></span></span><span class="line"><span class="cl"><span class="go">ID            : F746C44B-AB49-4D1A-803C-C55087343DC5
</span></span></span></code></pre></div><p>The output containing <code>Mount Point</code> confirms that a destination exists and its volume is reachable.</p>
<p>Confirm it points at your volume and not a replacement:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> defaults <span class="nb">read</span> /Library/Preferences/com.apple.TimeMachine.plist Destinations <span class="p">|</span> grep -A2 DestinationUUIDs
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">        DestinationUUIDs =         (
</span></span></span><span class="line"><span class="cl"><span class="go">            &#34;E3EA1B15-B920-4313-AB30-01E4AF10A27D&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">        );
</span></span></span></code></pre></div><p>That UUID should match the one from <code>diskutil apfs list</code> earlier. If it doesn&rsquo;t, macOS replaced your volume with one of its own, which is what happens when the <code>-role T</code> flag gets left out.</p>
<blockquote><p><strong>Note:</strong></p><code>ID</code> and <code>DestinationUUIDs</code> are different identifiers. One names the destination record and the other one names the volume it points at.</blockquote>

<h2 id="adding-exclusions">Adding Exclusions</h2>
<p>We can add paths we want to exclude from backups through the command line too.</p>
<p>There are three kinds of exclusions: fixed-path exclusions, sticky exclusions, and volume exclusions. But for our purposes we only care about fixed-path and sticky exclusions.</p>
<ul>
<li>Fixed-path exclusions are tied to a path regardless of what is there. Use these exclusions for anything that gets deleted and recreated, like build caches.</li>
<li>Sticky exclusions are the default. They&rsquo;re tied to the item itself. They follows the file if you move it and copies inherit it. Deleting and recreating a directory loses its stickiness.</li>
</ul>
<p>Here&rsquo;s an example of adding a fixed-path exclusion:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo tmutil addexclusion -p ~/Library/Developer/Xcode/DerivedData
</span></span></code></pre></div><p>Here&rsquo;s an example of adding a sticky exclusion (same command without the <code>-p</code> this time):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo tmutil addexclusion ~/some-directory
</span></span></code></pre></div><p>Check any path to make sure it was added to the exclusions. You should see <code>[Excluded]</code> next to the path (If you see <code>[UNKNOWN]</code> that means no file or directory is there, not that the exclusion didn&rsquo;t register):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil isexcluded ~/some-directory
</span></span><span class="line"><span class="cl"><span class="go">[Excluded]  /Users/nelson/some-directory
</span></span></span></code></pre></div><p>To list fixed-path exclusions we need to read them out of the preferences plist:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> defaults <span class="nb">read</span> /Library/Preferences/com.apple.TimeMachine.plist SkipPaths
</span></span><span class="line"><span class="cl"><span class="go">(
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;/Users/nelson/Library/Developer/Xcode/DerivedData&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">)
</span></span></span></code></pre></div><p>Sticky exclusions don&rsquo;t appear in the preferences and are stored as an extended attribute on the item:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> xattr -l ~/some-directory
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">com.apple.metadata:com_apple_backup_excludeItem: bplist00_com.apple.backupd
</span></span></span></code></pre></div><p>Removing them is similar to adding. We use <code>removeexclusion</code> instead. The <code>-p</code> flag is still necessary for removing fixed-path exclusions but not for sticky exclusions.</p>
<p>Here&rsquo;s an example of how to remove a fixed-path exclusion:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo tmutil removeexclusion -p ~/Library/Developer/Xcode/DerivedData
</span></span></code></pre></div><p>And here&rsquo;s an example of how to remove a sticky exclusion:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo tmutil removeexclusion ~/some-directory
</span></span></code></pre></div><h2 id="verifying-that-everything-worked">Verifying That Everything Worked</h2>
<p>Try manually starting a backup through the command line:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil startbackup --auto --block
</span></span></code></pre></div><p>The command above may look like it&rsquo;s stuck if your backup takes a while. You can run this in a separate terminal tab/window to monitor its progress:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil status
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Backup session status:
</span></span></span><span class="line"><span class="cl"><span class="go">{
</span></span></span><span class="line"><span class="cl"><span class="go">    ClientID = &#34;com.apple.backupd&#34;;
</span></span></span><span class="line"><span class="cl"><span class="go">    Percent = &#34;0.5771912029826294&#34;;
</span></span></span><span class="line"><span class="cl"><span class="go">    Running = 1;
</span></span></span><span class="line"><span class="cl"><span class="go">}
</span></span></span></code></pre></div><p>If you get an error like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">tmutil: Backup already in progress.
</span></span><span class="line"><span class="cl">POSIXError(_nsError: Error Domain=NSPOSIXErrorDomain Code=3 &#34;No such process&#34;)</span></span></code></pre></div><p>That just means macOS started a backup automatically.</p>
<p>Once it&rsquo;s done you can verify with:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil latestbackup
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">/Volumes/.timemachine/E3EA1B15-B920-4313-AB30-01E4AF10A27D/2026-08-01-005134.backup/2026-08-01-005134.backup
</span></span></span></code></pre></div><p>The path in the output confirms that a real backup exists. You can also check the result code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> defaults <span class="nb">read</span> /Library/Preferences/com.apple.TimeMachine.plist Destinations <span class="p">|</span> grep -E <span class="s2">&#34;RESULT|SnapshotDates&#34;</span> -A2
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">        RESULT = 0;
</span></span></span><span class="line"><span class="cl"><span class="go">        ReferenceLocalSnapshotDate = &#34;2026-08-01 08:24:45 +0000&#34;;
</span></span></span><span class="line"><span class="cl"><span class="go">        SMBConversionState = 0;
</span></span></span><span class="line"><span class="cl"><span class="go">        SnapshotDates =         (
</span></span></span><span class="line"><span class="cl"><span class="go">            &#34;2026-08-01 07:51:34 +0000&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">        );
</span></span></span></code></pre></div><p><code>RESULT = 0</code> means the backup was successful. Anything else means the last backup failed.</p>
<h2 id="storing-an-encrypted-drives-passphrase-in-apple-keychain">Storing an Encrypted Drive&rsquo;s Passphrase in Apple Keychain</h2>
<p>This only applies to encrypted drives.</p>
<p>From what I can tell, there&rsquo;s no way to store the Time Machine drive&rsquo;s passphrase in Apple Keychain using the command line. If you prefer your drive to unlock automatically when it&rsquo;s plugged into your machine, you&rsquo;ll need to do the following.</p>
<p>Eject the drive (change the path name to your drive&rsquo;s):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil eject /Volumes/backup
</span></span></code></pre></div><p>Plug it back in. When the password dialog appears, type the passphrase and check &ldquo;Remember this password.&rdquo; That&rsquo;ll save the passphrase in your local keychain so that macOS can unlock the drive automatically next time you plug it in. No need to type in the passphrase every time.</p>
<p>Confirm it worked by ejecting and replugging once more. If you aren&rsquo;t prompted to type in your passphrase, that means it worked. You can double check via the command line too:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil destinationinfo
</span></span></code></pre></div><p>If <code>Mount Point</code> is present, that means the drive unlocked and mounted.</p>
<h2 id="cleaning-up-older-time-machine-drives-from-apple-keychain">Cleaning Up Older Time Machine Drives From Apple Keychain</h2>
<p>If you go through this process a few times there&rsquo;s a good chance you&rsquo;ll have several Keychain entries for old Time Machine drives. Deleting a volume doesn&rsquo;t remove its Keychain entry, you&rsquo;ll have to do this manually.</p>
<p>Normally, these Keychain entries point at volumes. But since those volumes were deleted, the entries are pointing at volumes that no longer exist. We can run the following to list all relevant Keychain entries:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> security dump-keychain ~/Library/Keychains/login.keychain-db <span class="p">|</span> awk <span class="err">&#39;</span>
</span></span><span class="line"><span class="cl"><span class="go">/0x00000007 &lt;blob&gt;=/{l=$0; sub(/.*&lt;blob&gt;=&#34;/,&#34;&#34;,l); sub(/&#34;$/,&#34;&#34;,l); lbl=l}
</span></span></span><span class="line"><span class="cl"><span class="go">/&#34;acct&#34;&lt;blob&gt;=/{v=$0; sub(/.*&lt;blob&gt;=&#34;/,&#34;&#34;,v); sub(/&#34;$/,&#34;&#34;,v); a=v}
</span></span></span><span class="line"><span class="cl"><span class="go">/&#34;svce&#34;&lt;blob&gt;=/{v=$0; sub(/.*&lt;blob&gt;=&#34;/,&#34;&#34;,v); sub(/&#34;$/,&#34;&#34;,v); if(v==a &amp;&amp; v ~ /^[0-9A-Fa-f]{8}-/) print lbl&#34;  &#34;v}&#39;
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">backup  016C2F32-854B-4B94-8B87-DEA1774902CB
</span></span></span><span class="line"><span class="cl"><span class="go">backup  E3EA1B15-B920-4313-AB30-01E4AF10A27D
</span></span></span></code></pre></div><p>There&rsquo;s two <code>backup</code> entries. To find the one that actually points to a volume, run:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil apfs list <span class="p">|</span> grep -E <span class="s2">&#34;^\s+\+-&gt;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">    +-&gt; Volume disk5s2 E3EA1B15-B920-4313-AB30-01E4AF10A27D
</span></span></span></code></pre></div><p>So UUID <code>E3EA1B15-B920-4313-AB30-01E4AF10A27D</code> points to a volume. Which means UUID <code>016C2F32-854B-4B94-8B87-DEA1774902CB</code> is safe to delete. We can delete it like so:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> security delete-generic-password -s <span class="s2">&#34;016C2F32-854B-4B94-8B87-DEA1774902CB&#34;</span>
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">keychain: &#34;/Users/nelson/Library/Keychains/login.keychain-db&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">version: 512
</span></span></span><span class="line"><span class="cl"><span class="go">class: &#34;genp&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">attributes:
</span></span></span><span class="line"><span class="cl"><span class="go">    0x00000007 &lt;blob&gt;=&#34;backup&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">    0x00000008 &lt;blob&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;acct&#34;&lt;blob&gt;=&#34;016C2F32-854B-4B94-8B87-DEA1774902CB&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;cdat&#34;&lt;timedate&gt;=0x32303236303733313034303530325A00  &#34;20260731040502Z\000&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;crtr&#34;&lt;uint32&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;cusi&#34;&lt;sint32&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;desc&#34;&lt;blob&gt;=&#34;Encrypted Volume Password&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;gena&#34;&lt;blob&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;icmt&#34;&lt;blob&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;invi&#34;&lt;sint32&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;mdat&#34;&lt;timedate&gt;=0x32303236303733313034303530325A00  &#34;20260731040502Z\000&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;nega&#34;&lt;sint32&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;prot&#34;&lt;blob&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;scrp&#34;&lt;sint32&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;svce&#34;&lt;blob&gt;=&#34;016C2F32-854B-4B94-8B87-DEA1774902CB&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">    &#34;type&#34;&lt;uint32&gt;=&lt;NULL&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">password has been deleted.
</span></span></span></code></pre></div><p>We can then double check that we only have the necessary Keychain entries left:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> security dump-keychain ~/Library/Keychains/login.keychain-db <span class="p">|</span> awk <span class="err">&#39;</span>
</span></span><span class="line"><span class="cl"><span class="go">/0x00000007 &lt;blob&gt;=/{l=$0; sub(/.*&lt;blob&gt;=&#34;/,&#34;&#34;,l); sub(/&#34;$/,&#34;&#34;,l); lbl=l}
</span></span></span><span class="line"><span class="cl"><span class="go">/&#34;acct&#34;&lt;blob&gt;=/{v=$0; sub(/.*&lt;blob&gt;=&#34;/,&#34;&#34;,v); sub(/&#34;$/,&#34;&#34;,v); a=v}
</span></span></span><span class="line"><span class="cl"><span class="go">/&#34;svce&#34;&lt;blob&gt;=/{v=$0; sub(/.*&lt;blob&gt;=&#34;/,&#34;&#34;,v); sub(/&#34;$/,&#34;&#34;,v); if(v==a &amp;&amp; v ~ /^[0-9A-Fa-f]{8}-/) print lbl&#34;  &#34;v}&#39;
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">backup  E3EA1B15-B920-4313-AB30-01E4AF10A27D
</span></span></span></code></pre></div><p>However, this is just for the sake of being tidy. I don&rsquo;t think having these kinds of entries in Keychain affects macOS negatively in a significant way.</p>
<h2 id="references">References</h2>
<ul>
<li>

<a href="https://support.apple.com/guide/mac-help/back-up-your-mac-with-time-machine-mh35860/mac" target="_blank" rel="noopener">https://support.apple.com/guide/mac-help/back-up-your-mac-with-time-machine-mh35860/mac</a></li>
<li>

<a href="https://keith.github.io/xcode-man-pages/diskutil.8.html" target="_blank" rel="noopener">https://keith.github.io/xcode-man-pages/diskutil.8.html</a></li>
<li>

<a href="https://keith.github.io/xcode-man-pages/tmutil.8.html" target="_blank" rel="noopener">https://keith.github.io/xcode-man-pages/tmutil.8.html</a></li>
<li>

<a href="https://eclecticlight.co/2024/11/21/how-do-apfs-volume-roles-work/" target="_blank" rel="noopener">https://eclecticlight.co/2024/11/21/how-do-apfs-volume-roles-work/</a></li>
<li>

<a href="https://eclecticlight.co/2024/04/02/apfs-containers-and-volumes/" target="_blank" rel="noopener">https://eclecticlight.co/2024/04/02/apfs-containers-and-volumes/</a></li>
<li>

<a href="https://eclecticlight.co/2021/10/12/juggling-with-hfs-and-apfs-partitions-and-volumes-a-primer/" target="_blank" rel="noopener">https://eclecticlight.co/2021/10/12/juggling-with-hfs-and-apfs-partitions-and-volumes-a-primer/</a></li>
</ul>
]]></content:encoded></item><item><title>Failed Time Machine Backups Fill Up Your Internal Drive Too</title><link>https://nelson.cloud/failed-time-machine-backups-fill-up-your-internal-drive-too/?ref=rss</link><pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate><guid>https://nelson.cloud/failed-time-machine-backups-fill-up-your-internal-drive-too/?ref=rss</guid><description>Failed backups prevent older snapshots from being released. Old snapshots retain deleted files and can take up a bunch of space.</description><content:encoded><![CDATA[<p>A failed Time Machine backup stops macOS from releasing an old local snapshot, and that snapshot retains everything you delete.</p>
<p>A snapshot doesn&rsquo;t store data. It just prevents blocks from being freed. Every file that is deleted since that snapshot was taken has its blocks pinned by it. In my case, my backups had been failing since March (it&rsquo;s July) so the old snapshot was never released. This old snapshot ballooned up to 226GiB.</p>
<p>I thought anything related to failed Time Machine backups would only take up space on the external SSD that I use for backups, but that is not the case. While macOS did warn me that my backups were failing due to my external drive being full, it never said anything about the same failure taking up 226GiB on my local drive.</p>
<p>The other misleading part is that deleting files wasn&rsquo;t actually freeing up space!</p>
<p>Before I cleared the old snapshot, this is what my storage looked like. There were 974GiB used. At this time, I didn&rsquo;t know that 226GiB were being taken up by an old snapshot.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> df -h /System/Volumes/Data
</span></span><span class="line"><span class="cl"><span class="go">Filesystem      Size    Used   Avail Capacity iused ifree %iused  Mounted on
</span></span></span><span class="line"><span class="cl"><span class="go">/dev/disk3s5   1.8Ti   974Gi   861Gi    54%    1.6M  9.0G    0%   /System/Volumes/Data
</span></span></span></code></pre></div><p>I ran this to see local snapshots:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil listlocalsnapshots /
</span></span><span class="line"><span class="cl"><span class="go">com.apple.TimeMachine.2026-03-15-121124.local
</span></span></span><span class="line"><span class="cl"><span class="go">com.apple.TimeMachine.2026-07-30-071923.local
</span></span></span></code></pre></div><p>One of the snapshots was from today at the time of writing (2026-07-30), which is normal. The other snapshot was from 2026-03-15 (over 4 months old!), which is not normal.</p>
<p>More details with <code>diskutil</code>. Note the <code>Purgeable: Yes</code> lines. This means macOS would reclaim that space under disk pressure, but since I had 861GiB available that never happened.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> diskutil apfs listSnapshots disk3s5
</span></span><span class="line"><span class="cl"><span class="go">Snapshots for disk3s5 (2 found)
</span></span></span><span class="line"><span class="cl"><span class="go">|
</span></span></span><span class="line"><span class="cl"><span class="go">+-- 65156CB2-C515-478B-BAB4-333F3B069097
</span></span></span><span class="line"><span class="cl"><span class="go">|   Name:        com.apple.TimeMachine.2026-03-15-121124.local
</span></span></span><span class="line"><span class="cl"><span class="go">|   XID:         7888254
</span></span></span><span class="line"><span class="cl"><span class="go">|   Purgeable:   Yes
</span></span></span><span class="line"><span class="cl"><span class="go">|
</span></span></span><span class="line"><span class="cl"><span class="go">+-- 196FCBAF-037D-45CE-BB27-1F68E5627340
</span></span></span><span class="line"><span class="cl"><span class="go">    Name:        com.apple.TimeMachine.2026-07-30-071923.local
</span></span></span><span class="line"><span class="cl"><span class="go">    XID:         9579327
</span></span></span><span class="line"><span class="cl"><span class="go">    Purgeable:   Yes
</span></span></span><span class="line"><span class="cl"><span class="go">    NOTE:        This snapshot limits the minimum size of APFS Container disk3
</span></span></span></code></pre></div><p>According to 

<a href="https://support.apple.com/guide/mac-help/about-time-machine-local-snapshots-mh35933/mac" target="_blank" rel="noopener">these docs</a>, Apple says:</p>
<blockquote>
<p>These files are stored for up to 24 hours or until space is needed on the disk.</p>
</blockquote>
<p>And in 

<a href="https://support.apple.com/en-us/102154" target="_blank" rel="noopener">these other docs</a>, Apple says:</p>
<blockquote>
<p>Time Machine saves one snapshot of your startup disk approximately every hour, and keeps it for 24 hours. It keeps an additional snapshot of your last successful Time Machine backup until space is needed.</p>
</blockquote>
<p>Normally these snapshots expire in 24 hours. The last successful backup snapshot doesn&rsquo;t expire until space pressure forces it out. So the old snapshot on my machine was expected. But since backups were failing for months the older snapshot was taking up space and saving every file I deleted since then. It was waiting for a successful backup that had not taken place since.</p>
<p>I deleted the local one that was old. This doesn&rsquo;t affect the external backup drive and I&rsquo;m only giving up the ability to restore from that point in time without my external drive plugged in.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> sudo tmutil deletelocalsnapshots 2026-03-15-121124
</span></span><span class="line"><span class="cl"><span class="go">Deleted local snapshot &#39;2026-03-15-121124&#39;
</span></span></span></code></pre></div><p>Then I checked SSD storage again to see the difference under &ldquo;Used&rdquo;.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> df -h /System/Volumes/Data
</span></span><span class="line"><span class="cl"><span class="go">Filesystem      Size    Used   Avail Capacity iused ifree %iused  Mounted on
</span></span></span><span class="line"><span class="cl"><span class="go">/dev/disk3s5   1.8Ti   748Gi   1.1Ti    41%    1.6M   11G    0%   /System/Volumes/Data
</span></span></span></code></pre></div><p>&ldquo;Used&rdquo; went from 974GiB to 748GiB. So 226GiB was cleared up. Crazy.</p>
<p>Try checking your local drive for snapshots that are older than your typical backup schedule (e.g. if you back up weekly, look for snapshots older than a week). Hourly snapshots expire after 24 hours and it&rsquo;s normal to have several of these. The retained one is from your last successful backup. This is the one that stays around until space is needed. It&rsquo;s only as old as your last successful backup.</p>
<p>For example, here&rsquo;s what my snapshots look like now after everything has been fixed:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> tmutil listlocalsnapshots /
</span></span><span class="line"><span class="cl"><span class="go">Snapshots for disk /:
</span></span></span><span class="line"><span class="cl"><span class="go">com.apple.TimeMachine.2026-07-30-071923.local
</span></span></span><span class="line"><span class="cl"><span class="go">com.apple.TimeMachine.2026-07-30-084235.local
</span></span></span><span class="line"><span class="cl"><span class="go">com.apple.TimeMachine.2026-07-30-185721.local
</span></span></span><span class="line"><span class="cl"><span class="go">com.apple.TimeMachine.2026-07-30-202600.local
</span></span></span></code></pre></div><h2 id="references">References</h2>
<ul>
<li>

<a href="https://support.apple.com/en-us/102154" target="_blank" rel="noopener">https://support.apple.com/en-us/102154</a></li>
<li>

<a href="https://support.apple.com/guide/mac-help/about-time-machine-local-snapshots-mh35933/mac" target="_blank" rel="noopener">https://support.apple.com/guide/mac-help/about-time-machine-local-snapshots-mh35933/mac</a></li>
<li>

<a href="https://eclecticlight.co/2026/01/31/explainer-snapshots-2/" target="_blank" rel="noopener">https://eclecticlight.co/2026/01/31/explainer-snapshots-2/</a></li>
</ul>
]]></content:encoded></item><item><title>How to Install a Specific Version of a Homebrew Package with brew extract</title><link>https://nelson.cloud/how-to-install-a-specific-version-of-a-homebrew-package-with-brew-extract/?ref=rss</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate><guid>https://nelson.cloud/how-to-install-a-specific-version-of-a-homebrew-package-with-brew-extract/?ref=rss</guid><description>Use &lt;code&gt;brew extract&lt;/code&gt; to install a specific version of a homebrew package.</description><content:encoded><![CDATA[<p>I previously wrote about 

<a href="https://nelson.cloud/how-to-install-older-versions-of-homebrew-packages/">how to install older versions of homebrew packages</a>. That method involves installing a package from a Ruby file but it&rsquo;s outdated and doesn&rsquo;t always work. There&rsquo;s a better way with <code>brew extract</code>, although it still comes with caveats.</p>
<p>I&rsquo;ll be using <code>hugo</code> as an example. Let&rsquo;s say I wanted to install v0.145.0 because v0.146.0 introduced breaking changes that broke my theme.</p>
<blockquote><p><strong>tl;dr:</strong></p><p>To install hugo v0.145.0:</p>
<ul>
<li>Create a local tap with <code>brew tap-new $USER/local</code></li>
<li>Tap homebrew/core which is a 1.3GB clone at the time of writing</li>
<li>Extract the formula with <code>brew extract</code></li>
<li>Patch the <code>hugo</code> formula. This isn&rsquo;t needed for every formula.</li>
<li>Install as usual</li>
</ul></blockquote>

<p>Note that this process will point your <code>hugo</code> command to the older version, but you can switch between versions with <code>brew link</code>.</p>
<h2 id="create-a-local-tap">Create a local tap</h2>
<p>Run <code>brew tap-new $USER/local</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew tap-new <span class="nv">$USER</span>/local
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Initialized empty Git repository in /opt/homebrew/Library/Taps/nelson/homebrew-local/.git/
</span></span></span><span class="line"><span class="cl"><span class="go">[main (root-commit) 6af371f] Create nelson/local tap
</span></span></span><span class="line"><span class="cl"><span class="go"> 3 files changed, 111 insertions(+)
</span></span></span><span class="line"><span class="cl"><span class="go"> create mode 100644 .github/workflows/publish.yml
</span></span></span><span class="line"><span class="cl"><span class="go"> create mode 100644 .github/workflows/tests.yml
</span></span></span><span class="line"><span class="cl"><span class="go"> create mode 100644 README.md
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Created nelson/local
</span></span></span><span class="line"><span class="cl"><span class="go">/opt/homebrew/Library/Taps/nelson/homebrew-local
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">When a pull request making changes to a formula (or formulae) becomes green
</span></span></span><span class="line"><span class="cl"><span class="go">(all checks passed), then you can publish the built bottles.
</span></span></span><span class="line"><span class="cl"><span class="go">To do so, label your PR as `pr-pull` and the workflow will be triggered.
</span></span></span></code></pre></div><p>It will enable developer mode. This is normal and safe.</p>
<h2 id="tap-homebrewcore">Tap homebrew/core</h2>
<p>Next, run <code>brew tap --force homebrew/core</code>. At the time of writing, it&rsquo;s a 1.3GB download. This is necessary to get this working because Homebrew no longer keeps 

<a href="https://github.com/homebrew/homebrew-core" target="_blank" rel="noopener">homebrew-core</a> cloned locally. The <code>brew extract</code> command needs the full git history to search for older versions.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew tap --force homebrew/core
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">✔︎ JSON API formula.jws.json                                                                                                                                    Downloaded   32.0MB/ 32.0MB
</span></span></span><span class="line"><span class="cl"><span class="go">✔︎ JSON API cask.jws.json                                                                                                                                       Downloaded   15.4MB/ 15.4MB
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Tapping homebrew/core
</span></span></span><span class="line"><span class="cl"><span class="go">Cloning into &#39;/opt/homebrew/Library/Taps/homebrew/homebrew-core&#39;...
</span></span></span><span class="line"><span class="cl"><span class="go">remote: Enumerating objects: 3385552, done.
</span></span></span><span class="line"><span class="cl"><span class="go">remote: Counting objects: 100% (544/544), done.
</span></span></span><span class="line"><span class="cl"><span class="go">remote: Compressing objects: 100% (119/119), done.
</span></span></span><span class="line"><span class="cl"><span class="go">remote: Total 3385552 (delta 497), reused 427 (delta 425), pack-reused 3385008 (from 4)
</span></span></span><span class="line"><span class="cl"><span class="go">Receiving objects: 100% (3385552/3385552), 1.08 GiB | 48.36 MiB/s, done.
</span></span></span><span class="line"><span class="cl"><span class="go">Resolving deltas: 100% (2612327/2612327), done.
</span></span></span><span class="line"><span class="cl"><span class="go">Tapped 5 commands and 8313 formulae (8,851 files, 1.3GB).
</span></span></span></code></pre></div><h2 id="extract-the-desired-version">Extract the desired version</h2>
<p>Now we can use <code>brew extract</code>. This command will find a commit where the formula was at the version we want and copy that locally as <code>&lt;package&gt;@&lt;version&gt;.rb</code>.</p>
<p>In this case we want Hugo v0.145.0, so we run <code>brew extract --version=0.145.0 hugo $USER/local</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew extract --version<span class="o">=</span>0.145.0 hugo <span class="nv">$USER</span>/local
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Searching repository history
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Writing formula for hugo at 0.145.0 from revision a110fdb to:
</span></span></span><span class="line"><span class="cl"><span class="go">/opt/homebrew/Library/Taps/nelson/homebrew-local/Formula/hugo@0.145.0.rb
</span></span></span></code></pre></div><h2 id="patch-the-formula">Patch the formula</h2>
<p>This isn&rsquo;t needed for every formula and is something I ran into specifically with Hugo. Without this patch, you&rsquo;ll run into errors.</p>
<p>After running <code>brew extract</code>, edit the file: <code>/opt/homebrew/Library/Taps/$USER/homebrew-local/Formula/hugo@0.145.0.rb</code>.</p>
<p>Change this line:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">system</span> <span class="s2">&#34;go&#34;</span><span class="p">,</span> <span class="s2">&#34;build&#34;</span><span class="p">,</span> <span class="o">*</span><span class="n">std_go_args</span><span class="p">(</span><span class="ss">ldflags</span><span class="p">:,</span> <span class="ss">tags</span><span class="p">:)</span></span></span></code></pre></div><p>To this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">system</span> <span class="s2">&#34;go&#34;</span><span class="p">,</span> <span class="s2">&#34;build&#34;</span><span class="p">,</span> <span class="o">*</span><span class="n">std_go_args</span><span class="p">(</span><span class="ss">output</span><span class="p">:</span> <span class="n">bin</span><span class="o">/</span><span class="s2">&#34;hugo&#34;</span><span class="p">,</span> <span class="ss">ldflags</span><span class="p">:,</span> <span class="ss">tags</span><span class="p">:)</span></span></span></code></pre></div><p>The reason we need to patch this file is because it prevents the error:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">command not found: /opt/homebrew/Cellar/hugo@0.145.0/0.145.0/bin/hugo</span></span></code></pre></div><p>It&rsquo;s a mismatch between the path Homebrew expects (<code>bin/hugo</code>) vs the path that is created when using <code>brew extract</code> on Hugo (<code>bin/hugo@0.145.0</code>).</p>
<h2 id="install-the-older-version">Install the older version</h2>
<p>Now that Hugo is extracted and patched, we can install with <code>brew install hugo@0.145.0</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew install hugo@0.145.0
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">✔︎ JSON API cask.jws.json
</span></span></span><span class="line"><span class="cl"><span class="go">✔︎ JSON API formula.jws.json
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Fetching downloads for: hugo@0.145.0
</span></span></span><span class="line"><span class="cl"><span class="go">✔︎ Formula hugo@0.145.0 (0.145.0)
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Installing hugo@0.145.0 from nelson/local
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; go build -o=/opt/homebrew/Cellar/hugo@0.145.0/0.145.0/bin/hugo -tags=extended withdeploy -ldflags=-s -w -X github.com/gohugoio/hugo/common/hugo.commitHash=nelson -X github.com/gohugoio/hugo/common/
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; /opt/homebrew/Cellar/hugo@0.145.0/0.145.0/bin/hugo gen man --dir /opt/homebrew/Cellar/hugo@0.145.0/0.145.0/share/man/man1
</span></span></span><span class="line"><span class="cl"><span class="go">Warning: These files were overwritten during the `brew link` step:
</span></span></span><span class="line"><span class="cl"><span class="go">/opt/homebrew/etc/bash_completion.d/hugo
</span></span></span><span class="line"><span class="cl"><span class="go">.
</span></span></span><span class="line"><span class="cl"><span class="go">.
</span></span></span><span class="line"><span class="cl"><span class="go">.
</span></span></span><span class="line"><span class="cl"><span class="go">/opt/homebrew/share/zsh/site-functions/_hugo
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">They have been backed up to: /Users/nelson/Library/Caches/Homebrew/Backup
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Summary
</span></span></span><span class="line"><span class="cl"><span class="go">🍺  /opt/homebrew/Cellar/hugo@0.145.0/0.145.0: 53 files, 73MB, built in 8 seconds
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Running `brew cleanup hugo@0.145.0`...
</span></span></span><span class="line"><span class="cl"><span class="go">Disable this behaviour by setting `HOMEBREW_NO_INSTALL_CLEANUP=1`.
</span></span></span><span class="line"><span class="cl"><span class="go">Hide these hints with `HOMEBREW_NO_ENV_HINTS=1` (see `man brew`).
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Caveats
</span></span></span><span class="line"><span class="cl"><span class="go">zsh completions have been installed to:
</span></span></span><span class="line"><span class="cl"><span class="go">  /opt/homebrew/share/zsh/site-functions
</span></span></span></code></pre></div><p>Hugo v0.145.0 is now installed. There&rsquo;s a warning with long output in the previous example due to the normal Hugo package being already installed but that is expected. Homebrew is now pointing the <code>hugo</code> binary to v0.145.0 instead of the latest version (v0.160.1 at the time of writing). We can verify with <code>hugo version</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> hugo version
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">hugo v0.145.0+extended+withdeploy darwin/arm64 BuildDate=2025-02-26T15:41:25Z VendorInfo=brew
</span></span></span></code></pre></div><p>We can also see that Hugo v0.145.0 is installed along with the latest version with <code>brew list | grep hugo</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew list <span class="p">|</span> grep hugo
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">hugo
</span></span></span><span class="line"><span class="cl"><span class="go">hugo@0.145.0
</span></span></span></code></pre></div><h2 id="switching-between-versions-with-brew-link">Switching Between Versions with <code>brew link</code></h2>
<p>Currently the <code>hugo</code> command is pointing to v0.145.0. To have it point back to the regular version, run <code>brew unlink hugo &amp;&amp; brew link --overwrite hugo</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew unlink hugo <span class="o">&amp;&amp;</span> brew link --overwrite hugo
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Unlinking /opt/homebrew/Cellar/hugo/0.160.1... 2 symlinks removed.
</span></span></span><span class="line"><span class="cl"><span class="go">Linking /opt/homebrew/Cellar/hugo/0.160.1... 49 symlinks created.
</span></span></span></code></pre></div><p>And if we want <code>hugo</code> to point back to the old version, run <code>brew unlink hugo@0.145.0 &amp;&amp; brew link --overwrite hugo@0.145.0</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew unlink hugo@0.145.0 <span class="o">&amp;&amp;</span> brew link --overwrite hugo@0.145.0
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Unlinking /opt/homebrew/Cellar/hugo@0.145.0/0.145.0... 1 symlinks removed.
</span></span></span><span class="line"><span class="cl"><span class="go">Linking /opt/homebrew/Cellar/hugo@0.145.0/0.145.0... 48 symlinks created.
</span></span></span></code></pre></div><p>At first I expected <code>brew link --overwrite hugo</code> to work right off the bat, but running both <code>brew unlink</code> and <code>brew link --overwrite</code> is necessary to switch between versions properly. This is because Homebrew tracks linked formulas and actual symlinks on disk separately. To help Homebrew track things properly we need to run both <code>brew unlink</code> to clean the records, then <code>brew link --overwrite</code> to write the new symlinks.</p>
<p>There&rsquo;s no need to use <code>brew pin</code> to prevent the older version of Hugo from updating. Since this is a local copy, there is no remote repository that would be updated that would in turn update our local version. You can even try running <code>brew update</code> to see the warning message:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew update
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Updating Homebrew...
</span></span></span><span class="line"><span class="cl"><span class="go">Warning: No remote &#39;origin&#39; in /opt/homebrew/Library/Taps/nelson/homebrew-local, skipping update!
</span></span></span><span class="line"><span class="cl"><span class="go">Already up-to-date.
</span></span></span></code></pre></div><h2 id="removing-the-older-version">Removing the Older Version</h2>
<p>If you no longer need Hugo v0.145.0 you can run <code>brew uninstall hugo@0.145.0</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew uninstall hugo@0.145.0
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Uninstalling /opt/homebrew/Cellar/hugo@0.145.0/0.145.0... (53 files, 73MB)
</span></span></span></code></pre></div><p>If you don&rsquo;t have any other packages you extracted with <code>brew extract</code>, you can also remove your local tap with <code>brew untap $USER/local</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew untap <span class="nv">$USER</span>/local
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Untapping nelson/local...
</span></span></span><span class="line"><span class="cl"><span class="go">Untapped 1 formula (34 files, 36.7KB).
</span></span></span></code></pre></div><p>Finally, if you don&rsquo;t plan on using <code>brew extract</code> again in the future, you can remove the local clone of homebrew-core with <code>brew untap homebrew/core</code>. This will clean up the 1.3GB of files that was downloaded:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew untap homebrew/core
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Untapping homebrew/core...
</span></span></span><span class="line"><span class="cl"><span class="go">Untapped 5 commands and 8313 formulae (8,975 files, 1.3GB).
</span></span></span></code></pre></div><p>Then re-link <code>hugo</code> to the latest version with <code>brew unlink hugo &amp;&amp; brew link hugo</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew unlink hugo <span class="o">&amp;&amp;</span> brew link hugo
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Unlinking /opt/homebrew/Cellar/hugo/0.160.1... 2 symlinks removed.
</span></span></span><span class="line"><span class="cl"><span class="go">Linking /opt/homebrew/Cellar/hugo/0.160.1... 49 symlinks created.
</span></span></span></code></pre></div><h2 id="references">References</h2>
<ul>
<li>

<a href="https://docs.brew.sh/Manpage" target="_blank" rel="noopener">https://docs.brew.sh/Manpage</a></li>
<li>

<a href="https://github.com/orgs/Homebrew/discussions/2941" target="_blank" rel="noopener">https://github.com/orgs/Homebrew/discussions/2941</a></li>
<li>

<a href="https://emmer.dev/blog/installing-old-homebrew-formula-versions/" target="_blank" rel="noopener">https://emmer.dev/blog/installing-old-homebrew-formula-versions/</a></li>
</ul>
]]></content:encoded></item><item><title>Quick Tip: Mute the Terminal Login Message with a .hushlogin File</title><link>https://nelson.cloud/quick-tip-mute-the-terminal-login-message-with-a-.hushlogin-file/?ref=rss</link><pubDate>Sun, 28 Sep 2025 00:00:00 +0000</pubDate><guid>https://nelson.cloud/quick-tip-mute-the-terminal-login-message-with-a-.hushlogin-file/?ref=rss</guid><description>Create a .hushlogin file in your home directory to silence login messages.</description><content:encoded><![CDATA[<p>Today I learned that you can create an empty <code>.hushlogin</code> file in your home directory on macOS and Linux to hide the login message you get when starting up a new terminal window or tab.</p>
<p>I tried this on macOS but it should work on Linux too.</p>
<p>For example, when I start up a new terminal window/tab I see the following message:</p>
<img src="/mute-terminal-login-message/before.webp" alt="terminal with login message" width="980" height="254" style="max-width: 100%; height: auto; aspect-ratio: 980 / 254;" loading="lazy" decoding="async">
<p>After I create the <code>.hushlogin</code> file in my home directory, the login message goes away. First I created the file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">touch ~/.hushlogin</span></span></code></pre></div><p>Then I opened a new terminal window to verify that the message no longer shows up:</p>
<img src="/mute-terminal-login-message/after.webp" alt="terminal without login message after creating .hushlogin file" width="980" height="254" style="max-width: 100%; height: auto; aspect-ratio: 980 / 254;" loading="lazy" decoding="async">
<h2 id="references">References</h2>
<ul>
<li>

<a href="https://stackoverflow.com/questions/15769615/remove-last-login-message-for-new-tabs-in-terminal" target="_blank" rel="noopener">https://stackoverflow.com/questions/15769615/remove-last-login-message-for-new-tabs-in-terminal</a></li>
<li>

<a href="https://www.cyberciti.biz/howto/turn-off-the-login-banner-in-linux-unix-with-hushlogin-file/" target="_blank" rel="noopener">https://www.cyberciti.biz/howto/turn-off-the-login-banner-in-linux-unix-with-hushlogin-file/</a></li>
</ul>
]]></content:encoded></item><item><title>Remove Shadows From Screenshots in macOS</title><link>https://nelson.cloud/remove-shadows-from-screenshots-in-macos/?ref=rss</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0000</pubDate><guid>https://nelson.cloud/remove-shadows-from-screenshots-in-macos/?ref=rss</guid><description>Run this command to remove shadows from your screenshots in macOS: &lt;code&gt;defaults write com.apple.screencapture &amp;quot;disable-shadow&amp;quot; -bool &amp;quot;true&amp;quot;&lt;/code&gt;</description><content:encoded><![CDATA[<p>On macOS, screenshots of windows have an added drop shadow by default for whatever reason. Here&rsquo;s how to remove it:</p>
<p>To remove shadows from screenshots copy and paste this into the command line:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">defaults write com.apple.screencapture <span class="s2">&#34;disable-shadow&#34;</span> -bool <span class="s2">&#34;true&#34;</span></span></span></code></pre></div><br>
<p>To reset this setting and have shadows in your screenshots again run this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">defaults delete com.apple.screencapture <span class="s2">&#34;disable-shadow&#34;</span></span></span></code></pre></div><br>
<p>Alternatively, you can press <code>command</code> + <code>shift</code> + <code>4</code> and then press <code>space</code>. Then hold <code>option</code> before you click on a window to take a screenshot. This removes the drop shadow.</p>
<h2 id="references">References</h2>
<ul>
<li>

<a href="https://www.reddit.com/r/MacOS/comments/q7h3xl/any_way_to_take_a_screenshot_on_mac_without_the/" target="_blank" rel="noopener">https://www.reddit.com/r/MacOS/comments/q7h3xl/any_way_to_take_a_screenshot_on_mac_without_the/</a></li>
<li>

<a href="https://www.idownloadblog.com/2014/08/03/how-to-remove-the-shadow-window-screenshots-on-mac-os-x/" target="_blank" rel="noopener">https://www.idownloadblog.com/2014/08/03/how-to-remove-the-shadow-window-screenshots-on-mac-os-x/</a></li>
</ul>
<p>There were several other sites covering this but they didn&rsquo;t get right to the point and/or they were ad-ridden, so I decided to write a straightforward post about this.</p>
]]></content:encoded></item><item><title>Find Unnecessary Homebrew Packages with "brew leaves"</title><link>https://nelson.cloud/find-unnecessary-homebrew-packages-with-brew-leaves/?ref=rss</link><pubDate>Mon, 22 Jan 2024 00:00:00 +0000</pubDate><guid>https://nelson.cloud/find-unnecessary-homebrew-packages-with-brew-leaves/?ref=rss</guid><description>Use the &amp;lsquo;brew leaves&amp;rsquo; command to find potentially unnecessary Homebrew packages.</description><content:encoded><![CDATA[<p>

<a href="https://brew.sh/" target="_blank" rel="noopener">Homebrew</a> has a 

<a href="https://docs.brew.sh/Manpage#leaves---installed-on-request---installed-as-dependency" target="_blank" rel="noopener">&ldquo;brew leaves&rdquo;</a> command that shows all installed packages that are not depended on by other packages. That means that they can be uninstalled without causing issues to other installed Homebrew packages. It&rsquo;s good to regularly run this command to keep Homebrew from getting too bloated.</p>
<p>Here&rsquo;s what my <code>brew leaves</code> output looks like at the time of this writing:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew leaves
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">automake
</span></span></span><span class="line"><span class="cl"><span class="go">bat
</span></span></span><span class="line"><span class="cl"><span class="go">black
</span></span></span><span class="line"><span class="cl"><span class="go">coreutils
</span></span></span><span class="line"><span class="cl"><span class="go">ffmpeg
</span></span></span><span class="line"><span class="cl"><span class="go">go
</span></span></span><span class="line"><span class="cl"><span class="go">htop
</span></span></span><span class="line"><span class="cl"><span class="go">hugo
</span></span></span><span class="line"><span class="cl"><span class="go">jq
</span></span></span><span class="line"><span class="cl"><span class="go">libksba
</span></span></span><span class="line"><span class="cl"><span class="go">libpq
</span></span></span><span class="line"><span class="cl"><span class="go">libtool
</span></span></span><span class="line"><span class="cl"><span class="go">libyaml
</span></span></span><span class="line"><span class="cl"><span class="go">node
</span></span></span><span class="line"><span class="cl"><span class="go">openssl@1.1
</span></span></span><span class="line"><span class="cl"><span class="go">pkg-config
</span></span></span><span class="line"><span class="cl"><span class="go">postgresql@14
</span></span></span><span class="line"><span class="cl"><span class="go">python-typing-extensions
</span></span></span><span class="line"><span class="cl"><span class="go">tldr
</span></span></span><span class="line"><span class="cl"><span class="go">tree
</span></span></span><span class="line"><span class="cl"><span class="go">yt-dlp
</span></span></span><span class="line"><span class="cl"><span class="go">zlib
</span></span></span></code></pre></div><p>In my case, I know I don&rsquo;t need the <code>libpq</code> package anymore. So I can remove this package and then run <code>brew leaves</code> again to confirm it&rsquo;s gone.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew remove libpq
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Uninstalling /opt/homebrew/Cellar/libpq/16.1_1... (2,380 files, 29.9MB)
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew leaves
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">automake
</span></span></span><span class="line"><span class="cl"><span class="go">bat
</span></span></span><span class="line"><span class="cl"><span class="go">black
</span></span></span><span class="line"><span class="cl"><span class="go">coreutils
</span></span></span><span class="line"><span class="cl"><span class="go">ffmpeg
</span></span></span><span class="line"><span class="cl"><span class="go">go
</span></span></span><span class="line"><span class="cl"><span class="go">htop
</span></span></span><span class="line"><span class="cl"><span class="go">hugo
</span></span></span><span class="line"><span class="cl"><span class="go">jq
</span></span></span><span class="line"><span class="cl"><span class="go">libksba
</span></span></span><span class="line"><span class="cl"><span class="go">libtool
</span></span></span><span class="line"><span class="cl"><span class="go">libyaml
</span></span></span><span class="line"><span class="cl"><span class="go">node
</span></span></span><span class="line"><span class="cl"><span class="go">openssl@1.1
</span></span></span><span class="line"><span class="cl"><span class="go">pkg-config
</span></span></span><span class="line"><span class="cl"><span class="go">postgresql@14
</span></span></span><span class="line"><span class="cl"><span class="go">python-typing-extensions
</span></span></span><span class="line"><span class="cl"><span class="go">tldr
</span></span></span><span class="line"><span class="cl"><span class="go">tree
</span></span></span><span class="line"><span class="cl"><span class="go">yt-dlp
</span></span></span><span class="line"><span class="cl"><span class="go">zlib
</span></span></span></code></pre></div><p>And now <code>libpq</code> is gone! Try out <code>brew leaves</code> yourself. You may be surprised at the amount of things installed that you may not actually need.</p>
<h2 id="references">References</h2>
<ul>
<li>

<a href="https://docs.brew.sh/Manpage#leaves---installed-on-request---installed-as-dependency" target="_blank" rel="noopener">https://docs.brew.sh/Manpage#leaves---installed-on-request---installed-as-dependency</a></li>
</ul>
]]></content:encoded></item><item><title>Delete All node_modules Directories Recursively in macOS and Linux</title><link>https://nelson.cloud/delete-all-node_modules-directories-recursively-in-macos-and-linux/?ref=rss</link><pubDate>Sun, 14 May 2023 00:00:00 +0000</pubDate><guid>https://nelson.cloud/delete-all-node_modules-directories-recursively-in-macos-and-linux/?ref=rss</guid><description>How to delete all node_modules directories recursively in macOS and Linux systems.</description><content:encoded><![CDATA[<p>We can use the <code>find</code> command to delete a specific directory recursively. This is the command formula:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">find /path/to/starting/directory/ -type d -name <span class="s2">&#34;directory_to_delete&#34;</span> -exec rm -rf <span class="o">{}</span> <span class="se">\;</span></span></span></code></pre></div><p>For example, if we wanted to delete all <code>node_modules</code> directories within the path <code>/projects/javascript/</code>, we would run:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">find /projects/javascript/ -type d -name <span class="s2">&#34;node_modules&#34;</span> -exec rm -rf <span class="o">{}</span> <span class="se">\;</span></span></span></code></pre></div><blockquote><p><strong>Note:</strong></p><p>Sometimes the output says:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">find: ./node_modules: No such file or directory</span></span></code></pre></div><p>But the command should still work.</p>
</blockquote>

<p>If you look closely, we&rsquo;re really just executing a command against all <code>node_modules</code> directories in the <code>/projects/javascript/</code> directory (<code>rm -rf</code>). This command can be modified to execute other commands against all <code>node_modules</code> directories, but that is out of the scope of this post :)</p>
]]></content:encoded></item><item><title>How To Install Older Versions of Homebrew Packages</title><link>https://nelson.cloud/how-to-install-older-versions-of-homebrew-packages/?ref=rss</link><pubDate>Tue, 18 Apr 2023 00:00:00 +0000</pubDate><guid>https://nelson.cloud/how-to-install-older-versions-of-homebrew-packages/?ref=rss</guid><description>How to install a specific version of Homebrew packages.</description><content:encoded><![CDATA[<blockquote><p><strong>Warning: This method is outdated!:</strong></p><p>The approach outlined in this post still works in some cases, but as Homebrew has changed, this method has become unreliable. You may run into errors like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Error: Couldn&#39;t find manifest matching bottle checksum.</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Error: An exception occurred within a child process:
</span></span><span class="line"><span class="cl">  NoMethodError: undefined method &#39;user&#39; for nil</span></span></code></pre></div><p>A cleaner approach is <code>brew extract</code>, which copies the historical formula into a local tap so Homebrew has the context it needs. See my newer post instead: 

<a href="https://nelson.cloud/how-to-install-a-specific-version-of-a-homebrew-package-with-brew-extract/" target="_blank" rel="noopener">How to Install a Specific Version of a Homebrew Package with brew extract</a>.</p>
</blockquote>

<p>It&rsquo;s possible to install older versions of Homebrew packages by saving an older version of the corresponding Ruby file locally and running <code>brew install &lt;package&gt;.rb</code>. I&rsquo;ll use the <code>terraform</code> package as an example.</p>
<blockquote><p><strong>tl;dr:</strong></p><p>If I wanted to downgrade to Terraform 1.3.6, I would need to:</p>
<ul>
<li>Find the Ruby file for that specific version of 

<a href="https://github.com/Homebrew/homebrew-core/blob/169f333f93fe0703b542cdf75b1decd4cb78f68d/Formula/terraform.rb" target="_blank" rel="noopener">Terraform on the Homebrew GitHub repo</a></li>
<li>Download the Ruby file</li>
<li>Uninstall the current version of terraform by running <code>brew remove terraform</code></li>
<li>Install the older version defined in the Ruby file by running <code>HOMEBREW_DEVELOPER=true brew install --formulae terraform.rb</code></li>
</ul></blockquote>

<p>Let&rsquo;s say we have <code>terraform</code> version 1.4.5 but we need <code>terraform</code> version 1.3.6. We can start by browsing to 

<a href="https://github.com/Homebrew/homebrew-core/tree/master/Formula" target="_blank" rel="noopener">https://github.com/Homebrew/homebrew-core/tree/master/Formula</a> and try to find the formula for <code>terraform</code> under the <code>t</code> directory.</p>
<blockquote><p><strong>Note:</strong></p>Terraform has since been removed from 

<a href="https://github.com/Homebrew/homebrew-core" target="_blank" rel="noopener">homebrew-core</a> after its 

<a href="https://www.hashicorp.com/en/blog/hashicorp-adopts-business-source-license" target="_blank" rel="noopener">license change</a>, so the <code>blob/master</code> URL no longer exists. I&rsquo;ll be using a Terraform link pinned to a specific commit hash. For any package that is still in homebrew-core, the URL pattern previously described still applies: <code>https://github.com/Homebrew/homebrew-core/blob/master/Formula/&lt;directory-containing-package&gt;/&lt;package-name&gt;.rb</code></blockquote>

<img src="/how-to-install-older-versions-of-homebrew-packages/formulas.webp" alt="List of Homebrew formulas" width="720" height="410" style="max-width: 100%; height: auto; aspect-ratio: 3120 / 1780;" loading="lazy" decoding="async">
<p>Since there are a lot of files here, it&rsquo;s easier to just modify the URL path in the browser. Modify the path based on the directory the command is in: Take the name of the package and append it at the end of the url, adding <code>/&lt;directory-containing-package&gt;/&lt;package-name&gt;.rb</code> to the URL. The <code>.rb</code> is important because all Homebrew packages are defined in Ruby (files with the <code>.rb</code> extension).</p>
<p>In this case, we&rsquo;ll append <code>/t/terraform.rb</code> to the URL like so: 

<a href="https://github.com/Homebrew/homebrew-core/blob/6785b6baa9a6ce18c8230de9e9f0f847547dda9a/Formula/t/terraform.rb" target="_blank" rel="noopener">https://github.com/Homebrew/homebrew-core/blob/6785b6baa9a6ce18c8230de9e9f0f847547dda9a/Formula/t/terraform.rb</a></p>
<p>That URL will then take us to the Ruby file where the <code>terraform</code> Homebrew package is defined.</p>
<img src="/how-to-install-older-versions-of-homebrew-packages/terraform.webp" alt="Terraform Homebrew formula" width="720" height="410" style="max-width: 100%; height: auto; aspect-ratio: 3120 / 1780;" loading="lazy" decoding="async">
<p>Next, click the &ldquo;History&rdquo; link on the upper right above the code, or just click on this link 

<a href="https://github.com/Homebrew/homebrew-core/commits/master/Formula/t/terraform.rb" target="_blank" rel="noopener">https://github.com/Homebrew/homebrew-core/commits/master/Formula/t/terraform.rb</a>. In the next page, scroll down until you see the &ldquo;terraform: update 1.3.6 bottle&rdquo; link. Note that you may need to click on &ldquo;Browse History&rdquo; at the bottom of this page before continuing your search.</p>
<img src="/how-to-install-older-versions-of-homebrew-packages/1.3.6.webp" alt="Commit history for the terraform formula" width="720" height="410" style="max-width: 100%; height: auto; aspect-ratio: 3120 / 1780;" loading="lazy" decoding="async">
<p>Click on the 

<a href="https://github.com/Homebrew/homebrew-core/commit/169f333f93fe0703b542cdf75b1decd4cb78f68d" target="_blank" rel="noopener">terraform: update 1.3.6 bottle</a> link to see this page:</p>
<img src="/how-to-install-older-versions-of-homebrew-packages/commit.webp" alt="Commit for terraform 1.3.6" width="720" height="395" style="max-width: 100%; height: auto; aspect-ratio: 3840 / 2110;" loading="lazy" decoding="async">
<p>On the right side above the code block, click on the three dots, then click on &ldquo;View file&rdquo;.</p>
<img src="/how-to-install-older-versions-of-homebrew-packages/view-file.webp" alt="Three dots menu showing view file link" width="720" height="353" style="max-width: 100%; height: auto; aspect-ratio: 1872 / 918;" loading="lazy" decoding="async">
<p>This will take you to the 

<a href="https://github.com/Homebrew/homebrew-core/blob/169f333f93fe0703b542cdf75b1decd4cb78f68d/Formula/terraform.rb" target="_blank" rel="noopener">package formula for this specific version of terraform</a>.</p>
<img src="/how-to-install-older-versions-of-homebrew-packages/older-terraform.webp" alt="Formula for terraform 1.3.6" width="720" height="395" style="max-width: 100%; height: auto; aspect-ratio: 3840 / 2110;" loading="lazy" decoding="async">
<p>On the upper right side of the code block, click on &ldquo;Raw&rdquo;. This 

<a href="https://raw.githubusercontent.com/Homebrew/homebrew-core/169f333f93fe0703b542cdf75b1decd4cb78f68d/Formula/terraform.rb" target="_blank" rel="noopener">gives us the exact code we need</a> to install Terraform 1.3.6. Save the code locally to a file called <code>terraform.rb</code>. You can manually copy and paste or use <code>curl</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">curl https://raw.githubusercontent.com/Homebrew/homebrew-core/169f333f93fe0703b542cdf75b1decd4cb78f68d/Formula/terraform.rb &gt; terraform.rb</span></span></code></pre></div><p>Then, remove the existing package:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew remove terraform
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Uninstalling /usr/local/Cellar/terraform/1.4.5... (6 files, 69MB)
</span></span></span></code></pre></div><p>Then run <code>brew install</code> but specify the file you saved locally to install the older version. Note that as of 

<a href="https://github.com/Homebrew/brew/releases/tag/4.6.4" target="_blank" rel="noopener">Homebrew version 4.6.4</a> you can no longer install formulae directly from a file. You can get around this by specifying 

<a href="https://github.com/Homebrew/brew/pull/20414" target="_blank" rel="noopener">the environment variable</a> <code>HOMEBREW_DEVELOPER</code>.</p>
<p>So to install Terraform from the file we just downloaded, run <code>HOMEBREW_DEVELOPER=true brew install --formulae terraform.rb</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> <span class="nv">HOMEBREW_DEVELOPER</span><span class="o">=</span><span class="nb">true</span> brew install --formulae terraform.rb
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Fetching downloads for: terraform
</span></span></span><span class="line"><span class="cl"><span class="go">✔︎ Bottle Manifest terraform (1.3.6)
</span></span></span><span class="line"><span class="cl"><span class="go">✔︎ Bottle terraform (1.3.6)
</span></span></span><span class="line"><span class="cl"><span class="go">Warning: terraform 1.5.7 is available and more recent than version 1.3.6.
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Pouring terraform--1.3.6.arm64_ventura.bottle.tar.gz
</span></span></span><span class="line"><span class="cl"><span class="go">🍺  /opt/homebrew/Cellar/terraform/1.3.6: 7 files, 64MB
</span></span></span><span class="line"><span class="cl"><span class="go">==&gt; Running `brew cleanup terraform`...
</span></span></span><span class="line"><span class="cl"><span class="go">Disable this behaviour by setting `HOMEBREW_NO_INSTALL_CLEANUP=1`.
</span></span></span><span class="line"><span class="cl"><span class="go">Hide these hints with `HOMEBREW_NO_ENV_HINTS=1` (see `man brew`).
</span></span></span></code></pre></div><p>Now <code>terraform</code> version 1.3.6 is installed!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> terraform version
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Terraform v1.3.6
</span></span></span><span class="line"><span class="cl"><span class="go">on darwin_arm64
</span></span></span></code></pre></div><blockquote><p><strong>Pro Tip:</strong></p><p>You can pin the current version so it doesn&rsquo;t upgrade in the future.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">brew pin terraform</span></span></code></pre></div><p>The next time you run <code>brew upgrade</code> it will be skipped:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> brew upgrade
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Warning: Not upgrading 1 pinned package:
</span></span></span><span class="line"><span class="cl"><span class="go">terraform 1.5.7
</span></span></span></code></pre></div><p>When you&rsquo;re ready to upgrade, you can unpin it:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">brew unpin terraform</span></span></code></pre></blockquote>

<h2 id="references">References</h2>
<ul>
<li>

<a href="https://docs.brew.sh/Manpage" target="_blank" rel="noopener">https://docs.brew.sh/Manpage</a></li>
<li>

<a href="https://docs.brew.sh/FAQ#how-do-i-stop-certain-formulae-from-being-updated" target="_blank" rel="noopener">https://docs.brew.sh/FAQ#how-do-i-stop-certain-formulae-from-being-updated</a></li>
</ul>
]]></content:encoded></item><item><title>Cleaning Up Residual Files on macOS After Deleting Apps</title><link>https://nelson.cloud/cleaning-up-residual-files-on-macos-after-deleting-apps/?ref=rss</link><pubDate>Sun, 28 Feb 2021 00:00:00 +0000</pubDate><guid>https://nelson.cloud/cleaning-up-residual-files-on-macos-after-deleting-apps/?ref=rss</guid><description>Clean up residual files and directories after deleting macOS apps.</description><content:encoded><![CDATA[<p>After deleting apps on macOS, they tend to leave behind residual files and directories throughout the system. You can use the <code>find</code> command to find these files after an app has been deleted. I&rsquo;ll be deleting the LastPass app and removing its residual files as an example.</p>
<blockquote><p><strong>2024-10-13 Update:</strong></p><p>I recently discovered 

<a href="https://github.com/alienator88/Pearcleaner" target="_blank" rel="noopener">Pearcleaner</a>. You can use this app to delete other apps along with all the extra files and folders they create. I recommend you use this first and then continue reading this post if you want to look more deeply.</p>
<p>You can download Pearcleaner from the link above or install it with 

<a href="https://formulae.brew.sh/cask/pearcleaner" target="_blank" rel="noopener">Homebrew</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">brew install --cask pearcleaner</span></span></code></pre></blockquote>

<h2 id="searching-for-residual-files-and-directories">Searching for Residual Files and Directories</h2>
<p>To find directories and files related to LastPass, I ran a system-wide search using <code>find</code>. I excluded directories such as <code>/System/Volumes/Data</code> since those result in errors like &ldquo;Operation not permitted&rdquo;. I also excluded Homebrew directories that don&rsquo;t need to be cleaned up. You can add more directories as needed, just make sure to not add a trailing slash to the filepaths!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">find / <span class="se">\
</span></span></span><span class="line"><span class="cl">-not <span class="se">\(</span> -path /System/Volumes/Data -prune <span class="se">\)</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-not <span class="se">\(</span> -path /usr/local/Homebrew -prune <span class="se">\)</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-not <span class="se">\(</span> -path /usr/local/Cellar -prune <span class="se">\)</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-not <span class="se">\(</span> -path /usr/local/Caskroom -prune <span class="se">\)</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-name <span class="se">\*</span>lastpass<span class="se">\*</span> 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="p">|</span> grep -v -E <span class="s1">&#39;Operation not permitted|Permission denied|Not a directory&#39;</span></span></span></code></pre></div><p>The command may take some time to complete depending on your machine specs and amount of files you have. It took around ~10 minutes for me on a 2019 MacBook Pro with an i7 Intel CPU.</p>
<p>Here&rsquo;s the output I got from the command above. I can now go through each of these files and folders and decide if I want to delete them manually:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">/private/var/folders/m9/_7bg6tbn3636m1zzlzq33bwh0000gn/T/com.lastpass.lastpassmacdesktop
</span></span><span class="line"><span class="cl">/private/var/folders/m9/_7bg6tbn3636m1zzlzq33bwh0000gn/C/com.lastpass.lastpassmacdesktop
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Application Support/com.lastpass.lastpassmacdesktop
</span></span><span class="line"><span class="cl">/Users/nelson/Library/WebKit/com.lastpass.lastpassmacdesktop
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Preferences/com.lastpass.lastpassmacdesktop.plist
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Application Scripts/N24REP3BMN.lmi.lastpass.group
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Application Scripts/com.lastpass.lastpassmacdesktop.safariext
</span></span><span class="line"><span class="cl">/Users/nelson/Library/HTTPStorages/com.lastpass.lastpassmacdesktop.binarycookies
</span></span><span class="line"><span class="cl">/Users/nelson/Library/HTTPStorages/com.lastpass.lastpassmacdesktop
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Group Containers/N24REP3BMN.lmi.lastpass.group
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Group Containers/N24REP3BMN.lmi.lastpass.group/Library/Preferences/N24REP3BMN.lmi.lastpass.group.plist
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Group Containers/N24REP3BMN.lmi.lastpass.group/Library/Application Scripts/N24REP3BMN.lmi.lastpass.group
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Containers/com.lastpass.LastPass
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Containers/com.lastpass.lastpassmacdesktop.safariext
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Containers/com.lastpass.lastpassmacdesktop.safariext/Data/Library/Application Scripts/com.lastpass.lastpassmacdesktop.safariext
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Caches/com.crashlytics.data/com.lastpass.lastpassmacdesktop
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Caches/Homebrew/Cask/lastpass--4.116.0.dmg
</span></span><span class="line"><span class="cl">/Users/nelson/Library/Caches/com.lastpass.lastpassmacdesktop</span></span></code></pre></div><p>This could probably be automated all the way through the deletion step, but I prefer to double check what is actually going to be deleted.</p>
<p>Also, this <em>may</em> help to free up space on macOS, but I mainly did it because I like keeping my system tidy.</p>
<p>Try this out with whatever apps you&rsquo;ve deleted in the past. You can also try finding files and folders by specifying a company name. For example, replace <code>\*lastpass\*</code> with <code>\*microsoft\*</code> and see what you get!</p>
<h2 id="references">References</h2>
<ul>
<li>

<a href="https://stackoverflow.com/questions/4210042/how-do-i-exclude-a-directory-when-using-find" target="_blank" rel="noopener">https://stackoverflow.com/questions/4210042/how-do-i-exclude-a-directory-when-using-find</a></li>
</ul>
]]></content:encoded></item></channel></rss>