Can I remove the older revision package of duplicated snap packages?
While examining the snap packages that are installed in a system, I noticed that some packages have a duplicate, one having an over revision number while the other having a newer revision number. For such duplicated packages, my questions are:
- Why are they duplicated?
- Can I remove the older package to ensure better disk space management?
- How do I remove the older package?
Below are examples of packages that do and do not have duplicates:
$ du -hcs /var/lib/snapd/snaps/*
31M /var/lib/snapd/snaps/2048x_3.snap
286M /var/lib/snapd/snaps/atom_282.snap
4.0K /var/lib/snapd/snaps/bare_5.snap
72M /var/lib/snapd/snaps/bitwarden_58.snap
72M /var/lib/snapd/snaps/bitwarden_59.snap
196M /var/lib/snapd/snaps/blender_1113.snap
214M /var/lib/snapd/snaps/blender_1237.snap
9.1M /var/lib/snapd/snaps/canonical-livepatch_119.snap
9.1M /var/lib/snapd/snaps/canonical-livepatch_126.snap
148M /var/lib/snapd/snaps/chromium_1854.snap
148M /var/lib/snapd/snaps/chromium_1864.snap
17M /var/lib/snapd/snaps/chromium-ffmpeg_23.snap
18M /var/lib/snapd/snaps/chromium-ffmpeg_24.snap
....
~$ ls -lh /var/lib/snapd/snaps/
total 12G
-rw------- 2 root root 31M Aug 5 06:23 2048x_3.snap
-rw------- 2 root root 286M Aug 5 08:35 atom_282.snap
-rw------- 2 root root 4.0K Sep 22 18:17 bare_5.snap
-rw------- 1 root root 72M Oct 30 00:20 bitwarden_58.snap
-rw------- 1 root root 72M Dec 9 04:28 bitwarden_59.snap
-rw------- 1 root root 196M Nov 18 04:06 blender_1113.snap
-rw------- 1 root root 214M Dec 4 09:39 blender_1237.snap
-rw------- 2 root root 9.1M Nov 17 21:06 canonical-livepatch_119.snap
-rw------- 2 root root 9.1M Nov 22 22:39 canonical-livepatch_126.snap
-rw------- 1 root root 148M Dec 16 04:28 chromium_1854.snap
-rw------- 1 root root 148M Jan 8 08:33 chromium_1864.snap
-rw------- 1 root root 17M Sep 3 06:29 chromium-ffmpeg_23.snap
-rw------- 2 root root 18M Nov 29 14:23 chromium-ffmpeg_24.snap
....
On the system that I am looking at, the total disk space utilized by /var/lib/snapd/snaps/*
is 12,180.248 MB. The disk space of all the duplicated packages(i.e. older revision of the same package) is 4,163.1 MB. In short, the older revision packages currently takes up 34.18% of the 12,180.248 MB. This appears to be a cost to using SNAP apps that I had not realised before.
To answer your questions:
Why are they duplicated?
⇢ They're different revisions (versions), not duplications.
Can I remove the older package to ensure better disk space management?
⇢ Yes. It's your computer, after all.
How do I remove the older package?
You can do this in Terminal like this:
snap remove {snap} --revision={revision}
You can also tell the system how many past versions to limit itself to like this:
sudo snap set system refresh.retain=2
Note: The value must be between 2
and 20
, and a number like 2
or 3
is generally recommended to save storage space and allow a rollback in the event of a bad update.
If you would like to list all the snaps and their versions, you can run this command:
snap list --all
Which will give you something like:
Name Version Rev Tracking Publisher Notes
bare 1.0 5 latest/stable canonical✓ base
canonical-livepatch 10.0.1 119 latest/stable canonical✓ disabled
canonical-livepatch 10.1.2 126 latest/stable canonical✓ -
core 16-2.52 11798 latest/stable canonical✓ core,disabled
core 16-2.52.1 11993 latest/stable canonical✓ core
core18 20211028 2253 latest/stable canonical✓ base
core18 20211015 2246 latest/stable canonical✓ base,disabled
core20 20211115 1242 latest/stable canonical✓ base,disabled
core20 20211129 1270 latest/stable canonical✓ base
gnome-3-28-1804 3.28.0-19-g98f9e67.98f9e67 145 latest/stable canonical✓ disabled
gnome-3-28-1804 3.28.0-19-g98f9e67.98f9e67 161 latest/stable canonical✓ -
gnome-3-34-1804 0+git.3556cb3 77 latest/stable/… canonical✓ -
gnome-3-34-1804 0+git.3556cb3 72 latest/stable/… canonical✓ disabled
gnome-3-38-2004 0+git.cd626d1 87 latest/stable canonical✓ -
gnome-3-38-2004 0+git.6ba6040 76 latest/stable canonical✓ disabled
gtk-common-themes 0.1-52-gb92ac40 1515 latest/stable/… canonical✓ disabled
gtk-common-themes 0.1-59-g7bca6ae 1519 latest/stable/… canonical✓ -
snap-store 3.38.0-66-gbd5b8f7 558 latest/stable/… canonical✓ -
snap-store 3.38.0-64-g23c4c77 547 latest/stable/… canonical✓ disabled
snapd 2.53.2 14066 latest/stable canonical✓ snapd,disabled
snapd 2.53.4 14295 latest/stable canonical✓ snapd
Need a Script?
IMPORTANT: You will want to check the output of snap list --all
on your computer before continuing, and the following is a script that should not be copy/pasted without sanity checking if you are using a locale that is not en_US.UTF-8
.
The Script:
#!/bin/bash
# This script will remove disabled snap revisions.
set -eu
LANG=C snap list --all | awk '/disabled/{print $1, $3}' |
while read name rev; do
snap remove "$name" --revision="$rev"
done
This will run snap list -all
and extract the lines that contain the word disabled
. This will be different depending on your locale, so check the output of the function first, then update awk '/disabled/
to replace disabled
with the label that is found in your output.
Save the script to a file (for example scrub-snaps.sh
) and then set it as being executable:
sudo chmod +x scrub-snaps.sh
Now you can run it, remembering to use sudo
:
sudo ./scrub-snaps.sh
Note: sudo
was not part of the script, but can be added if you prefer to have it in there. Either way, you'll be prompted for a password if required.
Keeping at least one older version of a snap is inherent in the design.
Snap packages were originally designed for a variety of environments where there is often no human admin and/or no way to attach a keyboard and monitor...like phones or IOT devices. Resiliency is a critical requirement for these systems: If an application crashes or an upgrade is corrupted, some form of guaranteed rollback without human intervention is needed. Hence the requirement for at least one older version on-hand.
Folks on classic desktops and servers don't care much about that rollback capability. They like different snap design elements: The secure automatic upgrades that are independent of the OS, the read-only squashfs tamper-prevention, the process confinement, etc.
But it's all a single standard, so you get the rollback capability, too. Even if you think you won't use it.
You cannot "disable" the rollback capability of snaps -- it's not really a "feature" but a key design element.
Building on @matigo answer, I wrote a python script to automate the removal of disabled SNAP packages. It allows a user to visually check the snap packages before proceeding with (or not) the removal process. An example of what the executed script does is shown in the link.
remove_disabled_snap_pkgs.py
#!/bin/python3
''' This python script automates the removal of all disabled SNAP packages in
a system. Doing so helps free up the system's disk space. This outcome can be
significant in the situation where many disabled SNAP packages are retained in
the system.
'''
from subprocess import run, PIPE, CalledProcessError
from pathlib import Path
import sys
# Assumptions
SNAP_PKGS_PATH = Path('/var/lib/snapd/snaps/')
# Also, at a minimum, this directory has at least one xxx.snap file there.
def snap_list():
'''Function to execute a bash 'snap list' cmd and returns a Python
dictionary of info of the ACTIVE SNAPCRAFT pkgs in the system.
pkgs_dict = {Name : {'Version':'xxx', 'Rev':'xxx', 'Tracking':'xxx',
'Publisher':'xxx', 'Notes':'xxx'}
}
'''
try:
cmd = ['snap', 'list']
completed = run(cmd, check=True, stdout=PIPE)
except CalledProcessError as err:
print('ERROR:', err)
else:
headers = completed.stdout.decode('utf-8').splitlines()[0].split()
pkgs=[line.split() for line in
completed.stdout.decode('utf-8').splitlines()[1:]]
pkgs_dict = {}
for pkg in pkgs:
pkgs_dict[pkg[0]] = {i:pkg[n+1] for n, i in enumerate(headers[1:])}
return pkgs_dict
# 1. Get all SNAPCRAFT pkgs in system
all_path = sorted(SNAP_PKGS_PATH.glob('*.snap'))
all_size = sum([p.stat().st_size for p in all_path])
# 2. Get active SNAPCRAFT pkgs in system
active_snap_pkgs = snap_list()
active_path = [SNAP_PKGS_PATH / Path(k+'_'+v['Rev']+'.snap')
for k, v in active_snap_pkgs.items()]
active_size = sum([p.stat().st_size for p in active_path])
# 3. Display info and instructions in terminal
print(f'ALL (ACTIVE & DISABLED) SNAP PACKAGES IN SYSTEM:')
for n, i in enumerate(all_path):
size = i.stat().st_size
if i in active_path:
print(f'Active\t{size:>12}\t{i}')
else:
print(f' \t{size:>12}\t{i}')
# 4. Show stats on total size of All, Active & Disabled SNAPCRAFT packages
width = 12
disabled_size = all_size - active_size
print('\nSIZE OF SNAP PACKAGES:')
print(f'1. All : {all_size:>{width}} bytes')
print(f'2. Active : {active_size:>{width}} bytes')
print(f'2. Disabled : {disabled_size:>{width}} bytes or '
f'{(disabled_size/all_size):.2%} of All')
# 5. Make decision to remove or not to remove Disabled SNAPCRAFT packages
if disabled_size > 0:
print(f'\nREMOVE ALL DISABLED SNAP PACKAGES? [y/n]')
while True:
decision = input()
if decision in ['y', 'Y', 'yes', 'Yes', 'YES']:
print('Removal in progress... pls wait')
for p in all_path:
if p not in active_path:
stem = p.stem
bar_index = stem.index('_')
name = stem[:bar_index]
revision = stem[bar_index+1:]
cmd = ['sudo', 'snap', 'remove', name,
'--revision='+revision]
print(f"\n{' '.join(cmd)}")
run(cmd, stdout=sys.stdout, stderr=sys.stderr,
encoding='utf8')
print(f'\nREMOVE ALL DISABLED SNAP PACKAGES? COMPLETED.')
break
elif decision in ['n', 'N', 'no', 'No', 'NO']:
print(f'\nNO REMOVAL IS PERFORMED.')
break
else:
print('Please enter only "y" or "n":')
else:
print(f'\nNO REMOVAL IS NEEDED.')