[Share Experiences] 自动化程序辅助清理不需要的deb软件
Tofloor
poster avatar
182******91
deepin
2023-03-06 04:04
Author

Linux:获取两份dpkg软件列表,通过比较得知一个软件清单,其中列出一份列表中有而另一份列表中没有的软件

需求的起源

这个需求的直接起源,是本人想清理自己的Linux系统中的这样的软件:以前以依赖等形式安装进了系统,但并非使用者自己使用的软件。这样的软件,基本上是闲置的,而且会在dpkg相关软件列表中出现。

如果只是通过肉眼来观察和找出这样的软件,往往是低效的,易错的,易漏的。

现在,如果我手上有一份相对干净的软件列表,再用当前系统的软件列表,自动地与之做对比,可以快速找出这样的软件,即干净的软件列表中没有而当前系统软件列表中有的软件。这样的软件形成一份列表之后,用户就可以依据这个列表来快速地卸载这些软件,如果确实不需要。

准备工作

诸如在Debian系的Linux系统中,命令 dpkg -l可以列出当前系统中曾安装的软件及其状态。

运行该命令,可以得到如下的结果。

我们的需求是用程序自动处理相关数据,因此,应该将上述结果导出至特定文件中。比如可以使用终端的重定向功能:

dpkg -l > dpkg_output.txt

按照这样的方法,获取一个比较干净的系统的软件清单。比如在系统刚装好或者刚精简好的时候,运行相应的命令。同样,按照这样的方法,获取你当下的系统的软件清单,在这份清单里,应该是存在不少可以卸载的软件。

这两份文件,或者多份文件,应该取不同的名字,做好区分。

在用代码处理之前,我们已经获得了比如两份软件清单,一份是比较干净的清单,如 dpkg_output_orig.txt,一份是比较脏的清单,如 dpkg_output.txt

这两份文件中的实际数据之外的部分,比如前几行的说明和列名,应该直接删掉,方便后面进行处理。文件内容形如:

观察上面这样的数据,可以发现,这里存在5列数据,分别是状态、名称、版本、体系结构、描述。

实现需求的Python代码

Python语言可以考虑先用re.split()语句分割每行的数据成为列表,再将这样的列表转化为诸如DataFram这样的数据结构。有了DataFrame,就可以方便地筛选出我们需要的上述的那种清单。

代码如下:

import re
import pandas as pd


def get_df_from(filePath):
    global my_df
    """get dataframe from text for example."""
    with open(filePath, "r") as f:
        my_lines = f.readlines()

    my_list = []
    for line in my_lines:
        # line_list = re.split(r"\s{2,}", line)    # this is the standard method, but datas here is not clear.
        line_list = re.split(r"\s{2,}", line, 4)    # in this case, we need set split times as 4.
        my_list.append(line_list)

    my_columns = ["状态", "名称", "版本", "体系结构", "描述"]
    my_df = pd.DataFrame(my_list, columns=my_columns)
    print("lines: ", my_df.shape[0])
    return my_df


dpkg_1_df = get_df_from("dpkg_output_orig.txt")
dpkg_2_df = get_df_from("dpkg_output.txt")

# ~ for reverse
dpkg_filter = dpkg_2_df[(~dpkg_2_df["名称"].isin(dpkg_1_df["名称"]))
                        & (dpkg_2_df["状态"] == "ii")]

dpkg_filter_list = list(dpkg_filter.名称)
with open("dpkg_filter_list.txt", "w") as f:
    f.write("\n".join(dpkg_filter_list))

从文本文件获得相应DataFrame的过程,被抽象成了函数get_df_from(filePath)。

这个函数首先根据特定的文件路径,打开文件,并使每行成为一个字符串,这样的字符串构成一个列表my_lines。

对这个列表中的每行,通过re.split(),分割为5个列数据,这些数据又构成一个列表line_list。line_list放入my_list,形成嵌套列表。

这里需要解释一下re.split(r"\s{2,}", line, 4)的几个参数。

line表示需要分割的字符串。

r"\s{2,}"表示匹配的字符串。其中的 \s,表示匹配所有空白符。其中的 {2,},表示至少匹配2次。这样做,是为了避免对字符之间只有一个空格的情况,也进行分割。其中前面的r,表示原字符串。

4表示分割的次数。通常,如果软件列表中的描述部分中的空白符不超过1个,就不需要设置这个分割次数。但是,由于特殊的原因,目前不得不设置。原因另说。

现在,可以说,我们已经得到了需要的嵌套列表,该列表中的每一个小列表中保存了5种列数据。有了这样的嵌套列表,就可以方便地得到DataFrame。为了便于阅读,应该为DataFrame设置好列名。

这样,我们就可以实现DataFrame数据结构。通过它,可以获取这样的软件的清单:这些软件在干净的软件列表中是没有的,同时在脏的软件列表中又是有的。这样的清单中就包含着我们可以卸载的闲置软件。

筛选这个清单,需要两个并列条件,一个是说,脏列表中有而干净列表中没有的软件,另一个是说,这样的软件应该是目前仍然安装在系统上的。

对于前一个条件,需要解释的是,我们在运用.isin()时,还需要取反,也就是需要 ~

对于后一个条件,应该考虑这种情况:一个软件也许在dpkg结果中出现,但可能此前就已经卸载了,而只留下一些残留文件。我们所需的清单中,不需要包含这样的软件。所以设置了这后一个条件,来排除掉这样的软件等等。

完成了这样的筛选过程,就得到了作为筛选结果的DataFrame dpkg_filter

从这个筛选结果,进一步获取软件名称,形成一个列表。这就是我们一直提到的那份软件清单。可以将这份清单保存到存储设备上。

清单如下:

autoconf
automake
autotools-dev
bat
busybox
chafa
cloc
com.github.alacritty
deborphan
dwm
fcitx-mozc:amd64
fonts-freefont-ttf
fonts-texgyre
fuse3
gdb-minimal
gettext
gimagereader
gir1.2-atspi-2.0:amd64
gir1.2-harfbuzz-0.0:amd64
gir1.2-spiceclientglib-2.0:amd64
gir1.2-spiceclientgtk-3.0:amd64
git
git-man
goldendict
gstreamer1.0-x:amd64
htop
hyphen-en-us
intltool
kpackagelauncherqml
libalgorithm-diff-perl
libalgorithm-diff-xs-perl
libatk-bridge2.0-dev:amd64
(为节省版面,省略下方其他内容)

拉出了这份清单,就可以方便地卸载不需要的软件了。


Debug发现Deepin软件包描述存在问题

当使用语句 line_list = re.split(r"\s{2,}", line)时,程序会报错:

ValueError: 5 columns passed, passed data had 6 columns

经debug,发现问题出在诸如这些数据上面:

ii  deepin-album                                  5.10.9-1                              amd64        Album for UOS  Album is a fashion photo manager for viewing and organizing pictures.
ii  deepin-camera                                 1.4.9-1                               amd64        this package software for  UOS deepin-camera is a tool to view camera, and also a smart take photo and video in life.
rc  deepin-mail                                   5.4.14-1                                   amd64        Mail is an easy-to-use desktop mail client that can manage multiple email accounts,supporting IMAP and POP3 protocols.    Mail, developed by UnionTech Software, provides users with safe, convenient, free and value-added email services.

截图_选择区域_20230305134552.png

就是说,在这些软件包的描述部分,字符之间的空格有超过1个的。

因此,re.split()语句运行后,会使得这些软件包相应的列表的元素数量超过预期中的5个。

由于这些软件包形成的列表项数不能与程序中已经设定的预期列表项数相对应,就会像上面那样报错。

从这里还可以发现,软件包的描述部分出现问题的软件,都是Deepin系列的软件。

希望Deepin团队修复上述这个问题。

Reply Favorite View the author
All Replies
avatar
来者可追
deepin
2023-03-06 04:56
#1

apt autoremove 、apt clean等命令不就是干这事儿的吗?

Reply View the author
avatar
青稚
deepin
2023-03-06 04:57
#2

手动命令清理apt缓存的deb包,或者下载清理工具,不更省事吗?,你写的太繁琐了。

还不如手动清理,或者下载清理软件设置开机自启,自动清理。joy

Reply View the author
avatar
182******91
deepin
2023-03-06 05:11
#3
来者可追

apt autoremove 、apt clean等命令不就是干这事儿的吗?

有些包通过这些方式没法自动清理掉。我针对的就是这样的复杂情况😂

Reply View the author
avatar
182******91
deepin
2023-03-06 05:13
#4
青稚

手动命令清理apt缓存的deb包,或者下载清理工具,不更省事吗?,你写的太繁琐了。

还不如手动清理,或者下载清理软件设置开机自启,自动清理。joy

有些包通过这些方式没法自动清理掉。我针对的就是这样的复杂情况😂还有,以前莫名其妙装上了,但其实后面基本不用的软件,没法通过依赖关系自动清理掉

Reply View the author
avatar
delsin
deepin
2023-03-06 05:22
#5

星火应用商店里的应用管理器就可以卸载软件呀。

截图_ccc-app-manager_20230305212151.png

对于普通用户,用系统自带应用商店或应用管理器卸载界面应用就行了。至于一些依赖,普通用户能不动最好不要动,容易搞出问题。

Reply View the author
avatar
来者可追
deepin
2023-03-06 05:56
#6
182******91

有些包通过这些方式没法自动清理掉。我针对的就是这样的复杂情况😂

稍复杂点儿的情况用 dpkg -l 结合 dpkg --purge 或 aptitude purge "~c" 也可解决啊,还可以清理配置文件。分割行时用正则时可忽略描述部分的。

Reply View the author
avatar
SamLukeYes
deepin
2023-03-06 05:58
#7

重新发明 nix 系列joy

Reply View the author
avatar
神末shenmo
deepin
Spark-App
Q&A Team
2023-03-06 08:29
#8
182******91

有些包通过这些方式没法自动清理掉。我针对的就是这样的复杂情况😂还有,以前莫名其妙装上了,但其实后面基本不用的软件,没法通过依赖关系自动清理掉

我明白这个,所以我比较讨厌编译软件

话说有没有可以直接运行的zip包啊,伸手手

Reply View the author
avatar
joo
deepin
2023-03-07 00:32
#9

deborphan

deborphan finds "orphaned" packages on your system. It determines which
packages have no other packages depending on their installation and shows
you a list of these packages. It is most useful when finding libraries,
but it can be used on packages in all sections.

deb包经过20年的发展和使用,很早就有人遇到与你一样的需求,有很多的人有一样的需求就会有人提供解决办法,linux不缺工具(有gui的除外,基于命令行的工具多如牛毛),deborphan是在安全的前提下,最佳列出不再需要的依赖包。

其实这个工具搭配新立得或gtk的前端gtkdeborphan(没有qt的前端)使用是很方便的。

Reply View the author
avatar
joo
deepin
2023-03-07 00:44
#10
joo

deborphan

deborphan finds "orphaned" packages on your system. It determines which
packages have no other packages depending on their installation and shows
you a list of these packages. It is most useful when finding libraries,
but it can be used on packages in all sections.

deb包经过20年的发展和使用,很早就有人遇到与你一样的需求,有很多的人有一样的需求就会有人提供解决办法,linux不缺工具(有gui的除外,基于命令行的工具多如牛毛),deborphan是在安全的前提下,最佳列出不再需要的依赖包。

其实这个工具搭配新立得或gtk的前端gtkdeborphan(没有qt的前端)使用是很方便的。

清理依赖你需要有一些经验哦,有时候一些孤立的依赖包也是有必须的,因为一些软件的维护者不规范

Reply View the author
avatar
joo
deepin
2023-03-07 00:49
#11

修复你个头,一个空格和多个空格是一样的(在规范上),你应该修改你的代码。

Reply View the author