204

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
  • 58,727
rkmax
  • 2,381

8 Answers8

231

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.

Copied from comments:

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 sh -c 'rm /var/lib/snapd/cache/*'
ntc2
  • 144
popey
  • 2,425
132

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.

This needs to be run by a user that can add / remove snaps (a sudo -i session is likely the most reliable option) (On Ubuntu Core, non-root admin users might be able to run it without sudo)

If using non-English OS, set LANG=C for the snap list --all command. (e.g. running in a subshell ( export LANG=C; rest of command here; ) (or use your local version of "disabled" instead)

106

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
  • 58,727
mhadidg
  • 1,091
43

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
  • 58,727
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
  • 8,241
A. Sahin
  • 71
  • 1
  • 2
4

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
  • 58,727
4

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
  • 141
1

Using xargs to remove old versions:

LANG=C snap list --all | awk '$6~/disabled/{print $1" --revision="$3}' | xargs -rn2 sudo snap remove

awk argument:

$6~/disabled/   match 'disabled' in field 6

xargs arguments:

-r    if there are no arguments, then do not run
-n2   use 2 arguments per command line
ole1105
  • 11