184

I'm new to snap usage, I have few apps installed on my system, something that I notice when run the command df -h I found mounted different versions of the same snap:

/dev/loop0       143M   143M     0 100% /var/lib/snapd/snap/gravit-designer/7
/dev/loop1        82M    82M     0 100% /var/lib/snapd/snap/core/4110
/dev/loop7       198M   198M     0 100% /var/lib/snapd/snap/polarr/3
/dev/loop2        82M    82M     0 100% /var/lib/snapd/snap/core/4206
/dev/loop3       143M   143M     0 100% /var/lib/snapd/snap/gravit-designer/6
/dev/loop10      137M   137M     0 100% /var/lib/snapd/snap/gravit-designer/5

My question is why they keep there, the only way I found to remove the old is remove and install again the snap.

Is there something like prune to maintain my system?

1

7 Answers 7

210

Here's a short script which will remove all old versions of snaps. This will only keep the current active version, which should recover you some disk space:

#!/bin/bash
# Removes old revisions of snaps
# CLOSE ALL SNAPS BEFORE RUNNING THIS
set -eu

LANG=C snap list --all | awk '/disabled/{print $1, $3}' |
    while read snapname revision; do
        snap remove "$snapname" --revision="$revision"
    done

The "Close snaps" is there because you may not have restarted an application before you updated. So it's possible you're actually running a revision which is to be removed by the script.

8
  • 2
    It successfully removed all old versions, but no space is added to my disk!
    – mtoloo
    Jul 25, 2018 at 15:15
  • 1
    Check dir /var/lib/snapd/snaps/ before and after running this script. Should have free up some space - if really removed some snaps. It should show messages like snap-name removed, eg gtk-common-themes removed.
    – PeterM
    Sep 24, 2018 at 18:30
  • 4
    There are some hardlinks in /var/lib/snapd/cache so you must delete those too to free up space. You can safely remove the cache with sudo rm /var/lib/snapd/cache/*
    – rubo77
    Jun 4, 2019 at 2:00
  • 1
    strangely some snaps are not removed this way: gnome-3-28-1804 gnome-3-34-1804 gnome-3-38-2004
    – rubo77
    Nov 1, 2022 at 9:01
  • 1
    LANG=C snap list --all | awk '/disabled/{print "snap remove " $1 " --revision=" $3 }' | sh - Apr 12, 2023 at 9:03
113

A version of the script from another answer, as a one-liner, without the awk dependency:

snap list --all | while read snapname ver rev trk pub notes; do if [[ $notes = *disabled* ]]; then snap remove "$snapname" --revision="$rev"; fi; done

This likely requires bash or a compatible shell with the [[ construct.

7
  • 8
    This should be run from a user that can add snaps. On Ubuntu Core, the admin user works, on normal Ubuntu, a sudo -i session might be needed, or the snap remove might need to be run with sudo. Feb 4, 2019 at 17:06
  • 1
    @rubo77 pointed out that it does assume an English locale. Running it in a sub-shell (to not mess with the main shell's locale env variables) after doing export LC_ALL=en_US.UTF-8 beforehand should assure that. (It can also be set before the snap command, but I'm not sure if the removes later on might need to be translated as well) Jun 4, 2019 at 7:03
  • Just add LANG=c before the whole line works fine on German consoles
    – rubo77
    Jun 4, 2019 at 11:26
  • @rubo77 It should likely actually be LANG=C (or LC_ALL=C) for the default locale. Lowercase c might work due to C being the default for an invalid locale. (LC_MESSAGES is likely the minimal setting) (I don't want to edit the post for a setting that many users don't need though...) (You compare the errors of LANG=c locale with LANG=C locale) Jun 4, 2019 at 12:07
  • 2
    Yes, the --al output IS LOCALIZED , but if you know what is word for "disabled" in your language, you can just replace it in the command :) you can find out by just snap list --all
    – jave.web
    Mar 13, 2021 at 10:52
101

Starting from snap v2.34 and later, you can set the maximum number of snap revisions stored for each package by setting the refresh.retain option—it can only be a number between 2 and 20 and has a default value of 3.

sudo snap set system refresh.retain=2 
4
  • 7
    after doing this, moving from the default 3 to a new setting of 2, when are the current versions purged? Nov 14, 2018 at 23:36
  • 1
    I think the old snaps will be purged when new version installed. As you may already know, snap updates installed apps automatically depending on refresh.timer option, so you don't have to do the update manually
    – mhadidg
    Nov 15, 2018 at 6:12
  • But how to check how many my computer need? Example: refresh.retain=3 is good for 4Gb RAM or need more? Aug 9, 2019 at 20:46
  • 6
    @PeterKrauss It depends on your storage device capacity. It has nothing to do with your RAM capacity whatsoever.
    – mhadidg
    Aug 10, 2019 at 11:56
41

The snapd docs on versions state that the outdated revisions should be automatically removed so that no more than the last two revisions are installed. However, I also saw more than two versions of my snaps installed.

You can list all the revisions with snap list --all to see something like:

Name     Version                  Rev   Tracking  Developer  Notes
core     16-2.31.2                4206  stable    canonical  core,disabled
core     16-2.32.3                4407  stable    canonical  core,disabled
core     16-2.32.5                4486  stable    canonical  core
spotify  1.0.70.399.g5ffabd56-26  5     stable    spotify    disabled
spotify  1.0.72.117.g6bd7cc73-35  6     stable    spotify    disabled
spotify  1.0.77.338.g758ebd78-41  13    stable    spotify    -

You can remove individual revisions with

snap remove spotify --revision=5

This is safe even for the disabled revisions of core and other dependencies, and snap remove with an explicit --revision=... even prevents you from removing non-disabled snaps.

1
  • 1
    uh last two revisions meaning two plus the current one which is 3 revisions
    – Fuseteam
    May 28, 2021 at 13:04
7

The code @popey shared in their answer actually fails sometimes as some broken packages don't have the version info. So I modified the code to overcome this.

#!/bin/bash
# Removes old revisions of snaps
# CLOSE ALL SNAPS BEFORE RUNNING THIS
set -eu

snapsToRemove=$(LANG=en_US.UTF-8 snap list --all | awk '/disabled/{print $1, $2, $3}')

while read snapname version revision; do
    if [[ "$revision" == *[a-zA-z]* ]]; then
        # Version field is empty. Revision is in second field
        revision=$version
    fi
        snap remove "$snapname" --revision="$revision"
done <<< $snapsToRemove
2

In addition to other answers, I found a number of snap files of old versions that did not appear in the output of the snap list -all command. Those were mainly chromium and firefox.

So here is a perhaps over-engineered python script to remove snap files that do not correlate to any of the version listed in snap list -all (use with caution).

#!/usr/bin/env python3

import subprocess
from pathlib import Path

process = subprocess.run('snap list --all', shell=True, check=True, stdout=subprocess.PIPE)
text_lines = process.stdout.decode('utf-8').splitlines()
column_values_by_line = [
    [value for value in text_line.split(' ') if value]
    for text_line in text_lines
]
header_names = column_values_by_line[0]
snap_list = [
    dict(zip(header_names, column_values))
    for column_values in column_values_by_line[1:]
]
expected_snap_filenames = sorted([
    f'{snap["Name"]}_{snap["Rev"]}.snap'
    for snap in snap_list
])
print('expected snap files:', expected_snap_filenames)

snap_root_dir = '/var/lib/snapd/snaps'
existing_snap_filenames = sorted([
    path.name
    for path in Path(snap_root_dir).glob('*.snap')
])
print('actual snap files:', existing_snap_filenames)

obsolete_snap_filenames = sorted(set(existing_snap_filenames) - set(expected_snap_filenames))
print('obsolete snap files:', obsolete_snap_filenames)

if len(obsolete_snap_filenames) == len(existing_snap_filenames):
    raise AssertionError('something seems wrong, should not remove all of the snap files')

if obsolete_snap_filenames:
    remove_command = ['sudo', 'rm', '-f'] + [
        Path(snap_root_dir).joinpath(obsolete_snap_filename).as_posix()
        for obsolete_snap_filename in obsolete_snap_filenames
    ]
    print('running:', ' '.join(remove_command))
    user_input = input('Confirm? [Y/N] ')
    if not user_input.lower() in ('y', 'yes'):
        print('aborting')
    else:
        subprocess.run(remove_command, shell=False, check=True)
        print('done')
else:
    print('no obsolete snap files found')
1

I like to do it the safe way, manually, one by one!

snap list --all

Check out the duplicated ones and I think is logical to remove the lower revision, that indicates it is obsolete.

sudo snap remove <the snapname> --revision <lowest revision>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .