How to delete all but last [n] ZFS snapshots?
Solution 1:
You may find something like this a little simpler
zfs list -t snapshot -o name | grep ^tank@Auto | tac | tail -n +16 | xargs -n 1 zfs destroy -r
- Output the list of the snapshot (names only) with
zfs list -t snapshot -o name
- Filter to keep only the ones that match
tank@Auto
withgrep ^tank@Auto
- Reverse the list (previously sorted from oldest to newest) with
tac
- Limit output to the 16th oldest result and following with
tail -n +16
- Then destroy with
xargs -n 1 zfs destroy -vr
Deleting snapshots in reverse order is supposedly more efficient or sort in reverse order of creation.
zfs list -t snapshot -o name -S creation | grep ^tank@Auto | tail -n +16 | xargs -n 1 zfs destroy -vr
Test it with ...|xargs -n 1 echo
.
Solution 2:
More general case of getting most recent snapshot based on creation date, not by name.
zfs list -H -t snapshot -o name -S creation | head -1
Scoped to a specific filesystem name TestOne
zfs list -H -t snapshot -o name -S creation -d1 TestOne | head -1
-H
:No header so that first line is a snapshot name
-t snapshot
: List snapshots (list can list other things like pools and volumes)
-o name
: Display the snapshot name property.
-S creation
: Capital S
denotes descending sort, based on creation time. This puts most recent snapshot as the first line.
-d1 TestOne
: Says include children, which seems confusing but its because as far as this command is concerned, snapshots of TestOne are children. This will NOT list snapshots of volumes within TestOne such as TestOne/SubVol@someSnapshot
.
| head -1
: Pipe to head and only return first line.
Solution 3:
This totally doesn't answer the question itself, but don't forget you can delete ranges of snapshots.
zfs destroy zpool1/dataset@20160918%20161107
Would destroy all snapshots from "20160918" to "20161107" inclusive. Either end may be left blank, to mean "oldest" or "newest". So you could cook something up that figures out the "n" then destroy "...%n"..
Sorry to resurrect an old question.
Solution 4:
growse's didn't work on OpenIndiana for me. It didn't understand -0 for xargs.
If using sort, be aware that it sorts alphabetically which may not be desired as you are probably wanting to find the most recent.
Here is code that will delete all but the last snapshots.
Remove the 'echo' to go live.
RETENTION=5
FS=tank1/test
SNAPNAME=daily-
zfs list -t snapshot -o name | grep ^$FS@${SNAPNAME} | sed -n -e :a -e '1,${RETENTION}!{P;N;D;};N;ba' | xargs -n 1 echo zfs destroy -r
Sources: http://sed.sourceforge.net/sed1line.txt
Solution 5:
I may have solved this with some bash-fu.
zfs list -t snapshot -o name | grep ^tank@AutoD- | sort -r | wc -l | xargs -n 1 expr -$NUM_TO_KEEP + | tr -d '\n' | xargs -0 -i bash -c "zfs list -t snapshot -o name | grep ^tank@AutoD- | sort -r | tail -n{} | sort |xargs -t -n 1 zfs destroy -r"
Wow. It feels so wrong.