Skip to content

Instantly share code, notes, and snippets.

@SkyWriter
Last active January 24, 2024 04:30
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save SkyWriter/58e36bfaa9eea1d36460 to your computer and use it in GitHub Desktop.
Save SkyWriter/58e36bfaa9eea1d36460 to your computer and use it in GitHub Desktop.
#!/bin/bash
fsWithSnapshots=$(zfs list -Hr -t snapshot tank/share |grep '@' |cut -d '@' -f 1 |uniq)
for fs in $fsWithSnapshots ; do
# Changed to now sort newest to oldest. This will mean that newer snapshots without deltas will get removed.
emptySnapshot=$(zfs list -Hr -d1 -t snapshot -o name,used -S creation $fs |sed '$d' |awk ' $2 == "0B" { print $1 }' )
for snapshot in $emptySnapshot ; do
# Added safety check. Verify the size of the snapshot prior to destroying it
used=$(zfs list -Hr -d1 -t snapshot -o used $snapshot)
if [[ $used != "0B" ]]; then
continue
fi
echo "Destroying empty snapshot $snapshot"
zfs destroy $snapshot
done
done
@pboulanov
Copy link

Thanks - very useful!
Changed the 'tank/share' to my vdev/share and worked!

@DarwinAwardWinner
Copy link

FYI this script is broken, and will delete non-empty snapshots. See the explanation here: https://www.mail-archive.com/zfs-discuss@opensolaris.org/msg17752.html

@mailinglists35
Copy link

This works fine and carefully deletes zero sized snaps one by one

https://github.com/fracai/zfs-rollup/blob/master/clearempty.py

@TeTeHacko
Copy link

TeTeHacko commented May 21, 2017

zfs list -t snapshot | awk '$2 == 0 {print $1}' | xargs -r -n 1 /sbin/zfs destroy

@scottinan
Copy link

change line 7 to

emptySnapshot=$(zfs list -Hr -d1 -t snapshot -o name,used -s creation $fs | sed '$d' | awk ' $2 == "0B" { print $1 }' )

and it works again 👍

@StevenWolfe
Copy link

StevenWolfe commented Dec 6, 2020

FYI this script is broken, and will delete non-empty snapshots. See the explanation here: https://www.mail-archive.com/zfs-discuss@opensolaris.org/msg17752.html

^ This is correct. The script will delete snapshots that aren't actually zero bytes.

Here's a revised version -- it should avoid deleting snapshots that actually have data, and should preserve the first snapshot in which the change appeared:

#!/bin/bash

fsWithSnapshots=$(zfs list -Hr -t snapshot tank/share |grep '@' |cut -d '@' -f 1 |uniq)

for fs in $fsWithSnapshots ; do
  # Changed to now sort newest to oldest.  This will mean that newer snapshots without deltas will get removed.
  emptySnapshot=$(zfs list -Hr -d1 -t snapshot -o name,used -S creation $fs |sed '$d' |awk ' $2 == "0B" { print $1 }' )
  for snapshot in $emptySnapshot ; do

    # Added safety check.  Verify the size of the snapshot prior to destroying it
    used=$(zfs list -Hr -d1 -t snapshot -o used $snapshot)
    if [[ $used != "0B" ]]; then
      continue
    fi

    echo "Destroying empty snapshot $snapshot"
    zfs destroy $snapshot
  done
done

@SkyWriter
Copy link
Author

SkyWriter commented Dec 7, 2020

Thanks! I have updated the gist (especially now that it attracts so many people!) as well as my own scripts.

@segator
Copy link

segator commented Oct 23, 2022

is still safe this script?

@carwe
Copy link

carwe commented Jul 14, 2023

Hi
The reason this script (and surprisingly, all other scripts which fulfil the same task) has to iterate over the snapshots in reverse order and recheck the size is, that you are using the "used" property instead of the "written" property. The latter is exactly then zero when the snapshot is empty. And in case you wonder, it's from 2011: https://www.illumos.org/issues/1645

zfs create zroot/snaptest
zfs set mountpoint=/snaptest zroot/snaptest
cd /snaptest/

dd if=/dev/random bs=1M count=1 of=a
zfs snap zroot/snaptest@1

dd if=/dev/random bs=1M count=1 of=b
zfs snap zroot/snaptest@2

zfs snap zroot/snaptest@3

dd if=/dev/random bs=1M count=1 of=c
zfs snap zroot/snaptest@4

zfs snap zroot/snaptest@5

dd if=/dev/random bs=1M count=1 of=d
rm a
zfs snap zroot/snaptest@6

rm b
rm c
zfs snap zroot/snaptest@7

zfs snap zroot/snaptest@8

rm d
zfs snap zroot/snaptest@9

zfs list -o name,used,written zroot/snaptest -r -tall

NAME USED WRITTEN
zroot/snaptest 4.44M 0
zroot/snaptest@1 64K 1.10M
zroot/snaptest@2 0B 1.07M
zroot/snaptest@3 0B 0
zroot/snaptest@4 0B 1.07M
zroot/snaptest@5 0B 0
zroot/snaptest@6 64K 1.07M
zroot/snaptest@7 0B 64K
zroot/snaptest@8 0B 0
zroot/snaptest@9 0B 64K

@n0099
Copy link

n0099 commented Jan 24, 2024

https://gist.github.com/SkyWriter/58e36bfaa9eea1d36460?permalink_comment_id=3552336#gistcomment-3552336

Here's a revised version -- it should avoid deleting snapshots that actually have data, and should preserve the first snapshot in which the change appeared:

jimsalterjrs/sanoid#616 (comment)
https://www.reddit.com/r/zfs/comments/ja1k7n/sanoid_dont_create_empty_0b_snapshots/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment