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?

Giacomo1968
  • 55,001
rkmax
  • 2,171

7 Answers7

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.

popey
  • 2,216
  • 2
    It successfully removed all old versions, but no space is added to my disk! – mtoloo Jul 25 '18 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 '18 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 04 '19 at 02:00
  • Had to update awk print to $1 and $2 to work properly because $3 is Tracking at my end not Rev maybe because Version column is empty for some reason – Bashar Al-Abdulhadi Apr 24 '21 at 23:39
  • 1
    strangely some snaps are not removed this way: gnome-3-28-1804 gnome-3-34-1804 gnome-3-38-2004 – rubo77 Nov 01 '22 at 09:01
  • How is it even POSSIBLE to "close all snaps before running this" if one of the snaps is GNOME? – bvargo Apr 11 '23 at 15:38
  • 1
    LANG=C snap list --all | awk '/disabled/{print "snap remove " $1 " --revision=" $3 }' | sh - – Thorbjørn Ravn Andersen Apr 12 '23 at 09:03
  • There could be a bug in snap meaning snapd/snaps/ isn't getting cleared: https://superuser.com/questions/1811233/snap-list-all-does-not-show-everyting-in-var-lib-snapd-snaps – EoghanM Nov 15 '23 at 13:10
112

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.

Giacomo1968
  • 55,001
Gert van den Berg
  • 1,369
  • 1
  • 10
  • 14
  • 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. – Gert van den Berg Feb 04 '19 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) – Gert van den Berg Jun 04 '19 at 07:03
  • Just add LANG=c before the whole line works fine on German consoles – rubo77 Jun 04 '19 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) – Gert van den Berg Jun 04 '19 at 12:07
  • I had to add sudo before snap remove in the command in order for this to execute successfully. – fIwJlxSzApHEZIl Jul 03 '20 at 14:38
  • 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 '21 at 10:52
  • I just want to say it is utterly ridiculous to compress a do loop into a one liner. Makes it unnecessarily complex to read. But whatever! There are two different answers here and I guess this one is the one liner! – Giacomo1968 Jan 03 '24 at 20:50
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 
Giacomo1968
  • 55,001
mhadidg
  • 1,041
  • 1
  • 8
  • 12
  • 7
    after doing this, moving from the default 3 to a new setting of 2, when are the current versions purged? – Tim Richardson Nov 14 '18 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 '18 at 06:12
  • But how to check how many my computer need? Example: refresh.retain=3 is good for 4Gb RAM or need more? – Peter Krauss Aug 09 '19 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 '19 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.

Giacomo1968
  • 55,001
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

ccpizza
  • 7,763
A. Sahin
  • 71
  • 1
  • 1
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')

de1
  • 121
  • 2
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>
Giacomo1968
  • 55,001