問題描述
在網上瀏覽 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。