问题描述
在网上浏览 Ubuntu 文章时,我遇到了这个命令:
sudo dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge
作者说这是一个单行命令,会删除所有以前版本的Linux,只保留当前版本!
我实际上正在寻找这样的命令,但我不太确定这有多安全。我想知道:
-
执行这个命令是否安全?
-
这个命令是如何工作的?即解释这么大的命令的小部分
-
如果此命令用于某些不同的目的,那么实现作者声称的功能的正确命令是什么?
当我试图自己推论时,我变得非常困惑和沮丧。这个命令是如何工作的,它包含了许多很难用谷歌搜索的 /
、 |
、 \
、 *
和 ^
字符。
我正在寻找一步一步的翻译&我在互联网上找不到这个命令的解释!
最佳方法
我会说:不要以当前的形式使用它
-
它会在不询问您的情况下进行更改。
apt-get -y purge
部分允许 one-liner 开始执行清除包,而无需您的确认。如果脚本中存在任何错误,那么您可能会被搞砸。 -
没有来源,没有给出作者。它的来源在这里有所不同。如果它来自经过彻底测试的系统包,我们可以在其上跟踪正在执行的测试。从随机来源,我们不能相信它。
-
dpkg -l
在没有sudo
的情况下运行良好。我不明白为什么原作者认为这是必要的。
使用常识
删除有害部分并忽略任何以 root 身份运行的内容。
例如,将其缩减为:
dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'
它只输出内容并以常规用户权限运行。一旦您同意删除这些内核,您可以自己附加 | xargs sudo apt-get purge
。它故意没有 -y
选项,因此系统会要求您确认即将对系统进行的更改。
Explanation
-
dpkg -l
输出所有包的列表。在这种情况下,它只会列出以linux-
作为名称开头的包。 -
|
(管道)将左侧命令的输出(我们称之为stdout
)通过管道传输到右侧命令的输入(我们称之为stdin
)。 -
sed
是一个使用正则表达式操作字符串的工具。在这种情况下,它操作管道左侧的命令输出和已安装包的过滤器(依赖于dpkg
给出的ii
)。在这种情况下它甚至被嵌套。在这里解释sed
的整个使用太难了,因为它的使用对于复杂的正则表达式非常复杂。 (\(.*\)-\([^0-9]\+\)"
是一个正则表达式的例子。 -
Regular expressions 被非常广泛地用于根据它们所代表的表达式查找匹配项。
\1
是替换引用,用于执行某种通用 search-and-replace (引用第一个 ‘hit’ 和1
)。正则表达式本身不会造成任何伤害。但是,如果他们以错误的方式操作输入,他们可以让您删除错误的包,甚至进行 shell 注入。在这种情况下,它看起来像是一种根据uname -r
提供的版本查找内核包名称的方法。 -
uname -r
输出当前运行的内核版本。 -
xargs
将管道左侧的输入行作为参数附加到命令中。在这种情况下,每一行的内核版本被转换为水平空格分隔的列表并附加到sudo apt-get
命令。 -
sudo apt-get -y purge [packagename]
清除(删除所有内容)给定的包(作为参数)。
Alternatives
很多问题可能已经被问到了。到目前为止我发现的相关内容:
-
How do I remove old kernel versions to clean up the boot menu?
-
从 this answer 开始,以下命令似乎以更安全和更常见的方式执行相同操作:
sudo apt-get purge $( dpkg --list | grep -P -o "linux-image-\d\S+" | grep -v $(uname -r | grep -P -o ".+\d") )
次佳方法
你要求一个 step-by-step 解释所以这里是:
sudo dpkg -l 'linux-*'
列出包名中以 linux-
开头的包
| sed
并将列表通过管道传输到 sed
"s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'
这将使用非常复杂的正则表达式来编辑列表
| xargs
这会将新列表通过管道传输到 xargs
,它将作为参数发送给
sudo apt-get -y purge
这将清除这些包,而不会让您有机会改变主意。
或者更准确地说,它将将该列表发送到清除命令中并保留它。是否清除任何东西——重要的是——究竟清除了什么取决于前面命令的输出。
安全吗?在这种情况下,这一切都取决于您发现它的帖子的作者对正则表达式和 sed
语法的理解程度。并且有关于这两个主题的整本书。
第三种方法
我首先剖析命令,阅读每个命令的 man
页面。
-
dpkg -l
:列出 pacakges,因此dpkg -l linux-*
将列出所有以linux-
开头的包(通常是内核)。 -
sed
:dpkg -l linux-*
的输出通过sed
解码的几个正则表达式通过管道传输到sed
。 -
uname -r
uname
打印系统信息
uname – print system information
-r
句柄专门打印内核版本:
-r, –kernel-release print the kernel release
uname -r
的输出然后通过更多的正则表达式通过管道传送到 sed
,其输出被传递到 xargs
因此 xargs
将 sed
输出转换为包名称并将它们传递给 sudo apt-get purge -y
,sudo apt-get purge -y
会自动回答 ‘yes’ 的所有提示:
-y, –yes, –assume-yes Automatic yes to prompts; assume “yes” as answer to all prompts and run non-interactively. If an undesirable situation, such as changing a held package, trying to install a unauthenticated package or removing an essential package occurs then apt-get will abort. Configuration Item: APT::Get::Assume-Yes.
总而言之,这个命令似乎可以满足您的需求,但要确定我们必须翻译 sed
的正则表达式。
我刚跑:
dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'
这是一个屏幕截图:
所有旧内核版本 iirc。