linux_package_list
Linux 已安装软件包列表 美化工具
一键脚本
bash <(curl -sL gitee.com/meimolihan/linux-command_sh/raw/master/linux_package_list.sh)
效果预览
补充说明
该脚本用于美化显示 Linux 已安装软件包列表,自动检测当前系统的包管理器(dpkg/rpm/pacman/apk),适合快速查看系统安装的软件包详情。
功能特点
- 自动适配:自动检测包管理器并使用对应的查询命令(dpkg-query / rpm / pacman / apk)
- 彩色输出:软件包名(绿色)、版本(白色)、大小(蓝色)、类别(青色)、状态(绿色/灰色/黄色)使用不同颜色区分
- 过滤功能:支持传参过滤,只显示匹配的软件包
- 包总数统计:顶部显示软件包总数
- 表格对齐:使用
column命令自动对齐输出(如果可用)
输出说明
脚本输出包含以下字段(不同包管理器输出字段略有差异):
| 字段 | 说明 |
|---|---|
| 软件包 | 软件包的名称(绿色显示) |
| 版本 | 软件包的版本号(白色显示) |
| 大小 | 软件包占用的磁盘空间(蓝色显示) |
| 类别/分组 | 软件包的类别或分组信息(青色显示) |
| 状态 | 软件包安装状态:已安装(绿色)、未安装(灰色)、待移除(黄色) |
支持的系统
| 包管理器 | 系统 | 命令 |
|---|---|---|
| dpkg | Debian / Ubuntu / Deepin 等 | dpkg-query -W |
| rpm | CentOS / RHEL / Fedora / openSUSE 等 | rpm -qa |
| pacman | Arch Linux / Manjaro 等 | pacman -Q |
| apk | Alpine Linux | apk list -I |
注意事项
- 支持传参过滤:
脚本.sh 关键字只显示名称匹配的软件包 - 不传参则显示全部已安装软件包
- 需要
column命令(通常系统已自带,属于 util-linux 包) - 如果系统没有 column 命令,表格可能无法对齐,但不影响功能
脚本源码
传参:脚本.sh /软件包名 过滤显示匹配的软件包
不传参:脚本.sh 显示全部软件包
#!/bin/bash
set -uo pipefail
list_color_init() {
export gl_hui=$'\033[38;5;59m'
export gl_hong=$'\033[38;5;9m'
export gl_lv=$'\033[38;5;10m'
export gl_huang=$'\033[38;5;11m'
export gl_lan=$'\033[38;5;32m'
export gl_bai=$'\033[38;5;15m'
export gl_zi=$'\033[38;5;13m'
export gl_bufan=$'\033[38;5;14m'
export gl_cheng=$'\033[38;5;208m'
export reset=$'\033[0m'
export bold=$'\033[1m'
}
list_color_init
break_end() {
echo -e "\n${gl_lv}操作完成${reset}"
echo -en "${gl_bai}按任意键继续 ${gl_hong}.${gl_huang}.${gl_lv}.${gl_bai}${reset}"
read -r -n 1 -s -r -p ""
echo ""
clear
}
detect_pkg_manager() {
if [[ -n "${PKG_MANAGER_CACHED:-}" ]]; then
echo "$PKG_MANAGER_CACHED"
return
fi
local pm="unknown"
if command -v dpkg-query &> /dev/null; then
pm="dpkg"
elif command -v rpm &> /dev/null; then
pm="rpm"
elif command -v pacman &> /dev/null; then
pm="pacman"
elif command -v apk &> /dev/null; then
pm="apk"
fi
export PKG_MANAGER_CACHED="$pm"
echo "$pm"
}
count_packages() {
local search="${1:-}"
local pm=$(detect_pkg_manager)
local count=0
case "$pm" in
dpkg)
if [[ -n "$search" ]]; then
count=$(dpkg-query -W -f '${Package}\n' 2>/dev/null | grep -i "$search" | wc -l)
else
count=$(dpkg-query -W 2>/dev/null | wc -l)
fi
;;
rpm)
if [[ -n "$search" ]]; then
count=$(rpm -qa 2>/dev/null | grep -i "$search" | wc -l)
else
count=$(rpm -qa 2>/dev/null | wc -l)
fi
;;
pacman)
if [[ -n "$search" ]]; then
count=$(pacman -Q 2>/dev/null | cut -d' ' -f1 | grep -i "$search" | wc -l)
else
count=$(pacman -Q 2>/dev/null | wc -l)
fi
;;
apk)
if [[ -n "$search" ]]; then
count=$(apk list -I 2>/dev/null | cut -d' ' -f1 | grep -i "$search" | wc -l)
else
count=$(apk list -I 2>/dev/null | wc -l)
fi
;;
esac
echo "${count:-0}"
}
highlight_search() {
local text="$1"
local search="$2"
if [[ -z "$search" ]]; then
echo "$text"
return
fi
echo "$text" | sed "s/\($search\)/${gl_cheng}${bold}\1${reset}/gi"
}
list_beautify_packages_dpkg() {
local search="${1:-}"
local temp_file=$(mktemp)
dpkg-query -W -f '${Package}\t${Version}\t${Installed-Size}\t${Section}\t${Status}\n' 2>/dev/null | \
while IFS=$'\t' read -r pkg ver size section status; do
[[ -n "$search" && ! "$pkg" =~ $search ]] && continue
local st=""
local st_color=""
if [[ "$status" =~ installed ]]; then
st="已安装"
st_color="$gl_lv"
elif [[ "$status" =~ not-installed ]]; then
st="未安装"
st_color="$gl_hui"
elif [[ "$status" =~ deinstall ]]; then
st="待移除"
st_color="$gl_huang"
else
st="${status%% *}"
st_color="$gl_bai"
fi
local size_disp=""
if [[ -z "$size" || "$size" == "0" ]]; then
size_disp="-"
else
if command -v numfmt &> /dev/null; then
size_disp=$(numfmt --to=iec --suffix=B "$size" 2>/dev/null || echo "${size}KB")
else
size_disp="${size}KB"
fi
fi
local pkg_disp=$(highlight_search "$pkg" "$search")
printf "%s\t%s\t%s\t%s\t%s\n" \
"$pkg_disp" \
"${gl_bai}$ver${reset}" \
"${gl_lan}$size_disp${reset}" \
"${gl_bufan}$section${reset}" \
"${st_color}$st${reset}"
done > "$temp_file"
printf "${gl_hui}%-40s %-20s %-12s %-15s %-10s${reset}\n" \
"软件包" "版本" "大小" "类别" "状态"
printf "${gl_hui}%-40s %-20s %-12s %-15s %-10s${reset}\n" \
"$(printf '%0.s-' {1..40})" \
"$(printf '%0.s-' {1..20})" \
"$(printf '%0.s-' {1..12})" \
"$(printf '%0.s-' {1..15})" \
"$(printf '%0.s-' {1..10})"
if command -v column &> /dev/null; then
column -t -s $'\t' "$temp_file"
else
cat "$temp_file"
fi
rm -f "$temp_file"
}
list_beautify_packages_rpm() {
local search="${1:-}"
local temp_file=$(mktemp)
rpm -qa --queryformat '%{NAME}\t%{VERSION}-%{RELEASE}\t%{SIZE}\t%{GROUP}\n' 2>/dev/null | \
while IFS=$'\t' read -r pkg ver size group; do
[[ -n "$search" && ! "$pkg" =~ $search ]] && continue
local size_disp=""
if [[ -z "$size" || "$size" == "0" ]]; then
size_disp="-"
else
if command -v numfmt &> /dev/null; then
size_disp=$(numfmt --to=iec --suffix=B "$size" 2>/dev/null || echo "${size}B")
else
size_disp="${size}B"
fi
fi
local pkg_disp=$(highlight_search "$pkg" "$search")
printf "%s\t%s\t%s\t%s\n" \
"$pkg_disp" \
"${gl_bai}$ver${reset}" \
"${gl_lan}$size_disp${reset}" \
"${gl_bufan}$group${reset}"
done > "$temp_file"
printf "${gl_hui}%-50s %-25s %-12s %-20s${reset}\n" "软件包" "版本" "大小" "分组"
printf "${gl_hui}%-50s %-25s %-12s %-20s${reset}\n" \
"$(printf '%0.s-' {1..50})" \
"$(printf '%0.s-' {1..25})" \
"$(printf '%0.s-' {1..12})" \
"$(printf '%0.s-' {1..20})"
if command -v column &> /dev/null; then
column -t -s $'\t' "$temp_file"
else
cat "$temp_file"
fi
rm -f "$temp_file"
}
list_beautify_packages_pacman() {
local search="${1:-}"
local temp_file=$(mktemp)
pacman -Q 2>/dev/null | \
while read -r pkg ver; do
[[ -n "$search" && ! "$pkg" =~ $search ]] && continue
local pkg_disp=$(highlight_search "$pkg" "$search")
printf "%s\t%s\n" "$pkg_disp" "${gl_bai}$ver${reset}"
done > "$temp_file"
printf "${gl_hui}%-40s %-30s${reset}\n" "软件包" "版本"
printf "${gl_hui}%-40s %-30s${reset}\n" \
"$(printf '%0.s-' {1..40})" \
"$(printf '%0.s-' {1..30})"
if command -v column &> /dev/null; then
column -t -s $'\t' "$temp_file"
else
cat "$temp_file"
fi
rm -f "$temp_file"
}
list_beautify_packages_apk() {
local search="${1:-}"
local temp_file=$(mktemp)
apk list -I 2>/dev/null | sed 's/-[0-9].*_\|-[0-9].*\./-/' | \
while read -r pkg ver; do
[[ -n "$search" && ! "$pkg" =~ $search ]] && continue
local pkg_disp=$(highlight_search "$pkg" "$search")
printf "%s\t%s\n" "$pkg_disp" "${gl_bai}$ver${reset}"
done > "$temp_file"
printf "${gl_hui}%-40s %-30s${reset}\n" "软件包" "版本"
printf "${gl_hui}%-40s %-30s${reset}\n" \
"$(printf '%0.s-' {1..40})" \
"$(printf '%0.s-' {1..30})"
if command -v column &> /dev/null; then
column -t -s $'\t' "$temp_file"
else
cat "$temp_file"
fi
rm -f "$temp_file"
}
list_beautify_all() {
clear
local pm=$(detect_pkg_manager)
local filter="${1:-}"
local title=""
local func=""
case "$pm" in
dpkg)
title="已安装软件包列表 (dpkg)"
func="list_beautify_packages_dpkg"
;;
rpm)
title="已安装软件包列表 (rpm)"
func="list_beautify_packages_rpm"
;;
pacman)
title="已安装软件包列表 (pacman)"
func="list_beautify_packages_pacman"
;;
apk)
title="已安装软件包列表 (apk)"
func="list_beautify_packages_apk"
;;
*)
echo -e "${gl_hong}✗ 错误: 未检测到支持的包管理器 (dpkg/rpm/pacman/apk)${reset}"
exit 1
;;
esac
echo -e "${gl_zi}${bold}>>> $title${reset}"
if [[ -n "$filter" ]]; then
echo -e "${gl_huang}🔍 过滤: ${gl_cheng}${bold}$filter${reset}"
fi
local total=$(count_packages "$filter")
echo -e "${gl_lan}📦 软件包总数: ${bold}${total}${reset}"
echo -e "${gl_bufan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${reset}"
$func "$filter"
echo -e "\n${gl_bufan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${reset}"
break_end
}
if [[ $# -gt 0 ]]; then
list_beautify_all "$*"
else
list_beautify_all ""
fi
创建本地脚本
new_script="new_test.sh"
cat > "$new_script" << 'EOF'
#!/bin/bash
# 粘贴脚本源码
EOF
# 保留本地脚本,去掉 rm -f "$new_script"
chmod +x "$new_script" && ./"$new_script" && rm -f "$new_script"