我想知道一种清理 var/cache/apt 文件夹的方法,以便如果软件包有多个版本则仅保留最新版本,或者如果它是该程序的唯一软件包则保留该软件包。
例如,我有几个 vlc 包(vlc_1.1.11、vlc_1.1.12..)和几个 wine 包(wine1.3_1.3.34、wine1.3_1.3.35、wine1.3_1.3.36、wine1.3_1.3.37...)以及许多类似的包。
那么如何清理这个文件夹,让它只留下最新的软件包呢?目前我有 2.5GB 的空间,其中大部分都是较旧的软件包和较新的软件包混在一起的。
答案1
使用 apt-get 或 aptitude 的 autoclean 选项
sudo apt-get autoclean
sudo aptitude autoclean
来自手册页
干净的
clean 清除本地存储库中检索到的软件包文件。它会从 /var/cache/apt/archives/ 和 /var/cache/apt/archives/partial/ 中删除除锁定文件之外的所有内容。
自动清洁
与 clean 类似,autoclean 会清除本地存储库中检索到的软件包文件。不同之处在于,它只会删除无法再下载且基本无用的软件包文件。这样可以长期维护缓存,而不会失控。
答案2
我建议使用以下 bash 脚本
#!/bin/bash
cd /var/cache/apt/archives/
printf '%s\n' *.deb |
awk -F_ '{ print $1 }' |
sort -u |
while read pkg; do
pkg_files=($(ls -t "$pkg"_*.deb))
nr=${#pkg_files[@]}
if ((nr > 1)); then
unset pkg_files[0]
echo rm "${pkg_files[@]}"
fi
done
如果您对输出列表满意,请echo
从该行中删除。rm
它能做什么?
- 它列出所有 deb 包文件
- 删除文件名中从第一个
"_"
到最后一个的所有内容,获取包名称 - 对姓名进行排序,删除重复项
对于每个名字
- 按时间顺序列出与该名称对应的包文件
- 计算列表中包文件的数量
如果列表中有多个包
- 从列表中删除第一个较新的文件
- 从磁盘中删除与该名称对应的所有其他文件
可以提高效率,通过仅列出与从sort
和之间的差异中获得的包名称相对应的包文件sort -u
。
答案3
需要强调的是apt-get autoclean
,并不是aptitude autoclean
删除旧版本,而是删除存储库中不再存在的过时软件包。
此外,其他答案中提出的脚本忽略了数据包的体系结构,这意味着如果您有不同体系结构的包,则只会保留一个,其他的将被删除
也就是说,没有一个可用的答案可以提供全面的解决方案。因此,这里有一个命令行作为其他答案的替代方案:
$ basename -a /var/cache/apt/archives/*.deb | cut -d _ -s -f 1,3 --output-delimiter=_*_ | uniq -d | xargs -I{} sh -c "find /var/cache/apt/archives/ -maxdepth 1 -name {} -print | sort -V | head -n -1" | xargs -r sudo rm
解释
basename -a /var/cache/apt/archives/*.deb
列出所有文件名,但不包含其完整路径。
cut -d _ -s -f 1,3 --output-delimiter=_*_
用星号 ( ) 替换软件包版本,*
保留基本软件包名称(前缀)及其体系结构(后缀)。
uniq -d
删除重复的条目并同时删除没有重复的条目。
xargs -I{} sh -c
对于每个条目执行引号中的命令并{}
用输入文件掩码替换模式。
find /var/cache/apt/archives/ -maxdepth 1 -name {} -print
在档案目录中执行非递归搜索,将目标图案打印结果输出到标准输出。
sort -V
对每次搜索的结果进行排序。
head -n -1
删除最后一个结果,即数值最高的版本结果(其他结果最终将被删除,但最后一个结果将保留)。
xargs -r sudo rm
将结果从全部一起搜索并将它们传递给以超级用户权限执行的删除命令。
答案4
我提出了一个更简单、更人性化的 bash 脚本,基于恩佐替布算法,它不会像原始算法那样删除多余的文件:
#! /usr/bin/env bash
cd /var/cache/apt/archives/
for pkg in `ls *.deb | cut -d _ -f 1 | sort -u`; do
if [ $(ls $pkg\_* | wc -l) -gt 1 ]; then
files=$(ls -vr $pkg\_*)
rmfiles=`echo $files | cut -d " " -f 2-`
rm -v $rmfiles
fi
done