Linux 软件推荐
列表
| 名称 | ID (apt) | ID (dnf) | 描述 |
|---|---|---|---|
| cadaver | cadaver |
command-line WebDAV client | |
| aria2 | aria2 |
aria2 |
High speed download utility |
linux.sh
· 4.6 KiB · Bash
Raw
#!/usr/bin/env bash
BASE_URL="https://gist.asfd.cn/jetsung/linux/raw/HEAD/"
LIST_FILE="apt.txt" # 默认列表文件(可被自动切换或 -n 覆盖)
DESC_FILE="README.md" # 描述 Markdown 文件
EXTRA=""
VERBOSE=false # -v: 只显示详细信息,不安装
# 参数解析
parameters() {
while getopts "e:n:v" opt; do
case $opt in
e) EXTRA="$OPTARG" ;;
n) LIST_FILE="$OPTARG" ;;
v) VERBOSE=true ;;
\?) echo "无效参数: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
EXTRA="$EXTRA $@"
}
# 检测包管理器并返回命令(如 "apt" 或 "dnf" 或 "yum")
detect_package_manager() {
if command -v apt >/dev/null 2>&1; then
echo "apt"
elif command -v dnf >/dev/null 2>&1; then
echo "dnf"
elif command -v yum >/dev/null 2>&1; then
echo "yum"
else
echo "none"
fi
}
# 主函数
main() {
parameters "$@"
# 如果 LIST_FILE 没有扩展名,自动添加 .txt
if [[ "$LIST_FILE" != *.* ]]; then
LIST_FILE="${LIST_FILE}.txt"
fi
URL_DESC="${BASE_URL}${DESC_FILE}"
# -v 模式:解析 README.md 并显示软件详细信息
if $VERBOSE; then
echo "从 $URL_DESC 获取软件描述信息..."
echo
curl -s --fail "$URL_DESC" | awk '
/^\|.*\|.*\|.*\|.*\|$/ && NR > 2 { # 匹配数据行,跳过表头和分隔线
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "") # 去除行首尾空白
split($0, fields, "|")
if (length(fields) < 5) next
# 名称(第2列)
name_raw = fields[2]
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", name_raw)
# 支持 [text](url) 或 **text**
if (match(name_raw, /\[([^]]+)\]/) || match(name_raw, /\*\*([^*]+)\*\*/)) {
name = substr(name_raw, RSTART + (substr(name_raw, RSTART, 1) == "[" ? 1 : 2),
RLENGTH - (substr(name_raw, RSTART, 1) == "[" ? 2 : 4))
} else {
name = name_raw
}
# apt ID(第3列,可能有 ` 或空)
apt_raw = fields[3]
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", apt_raw)
gsub(/`/, "", apt_raw)
if (apt_raw == "") apt_raw = "(无)"
# dnf ID(第4列,可能为空)
dnf_raw = fields[4]
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", dnf_raw)
gsub(/`/, "", dnf_raw)
if (dnf_raw == "") dnf_raw = "(无)"
# 描述(第5列)
desc = fields[5]
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", desc)
if (name == "" || desc == "") next
printf "名称: %s\napt 包名: %s\ndnf 包名: %s\n描述: %s\n\n", name, apt_raw, dnf_raw, desc
}'
echo
exit 0
fi
# 正常模式:检测包管理器
PM=$(detect_package_manager)
case "$PM" in
apt)
BASE_CMD="sudo apt install -y"
PM_NAME="apt"
;;
dnf)
BASE_CMD="sudo dnf install -y"
PM_NAME="dnf"
;;
yum)
BASE_CMD="sudo yum install -y"
PM_NAME="yum"
;;
none)
echo "错误: 未检测到支持的包管理器(apt、dnf 或 yum)!" >&2
exit 1
;;
esac
# 自动切换列表文件(如果检测到 dnf/yum 且存在 dnf.txt)
if [[ "$PM" == "dnf" || "$PM" == "yum" ]]; then
if [[ "$LIST_FILE" == "apt.txt" ]] && curl -s --head --fail "${BASE_URL}dnf.txt" >/dev/null; then
LIST_FILE="dnf.txt"
echo "检测到 $PM_NAME 系统,自动切换到 dnf.txt 列表文件。"
fi
fi
URL_LIST="${BASE_URL}${LIST_FILE}"
echo "从 $URL_LIST 下载软件列表..."
SOFTS=$(curl -s --fail "$URL_LIST" | grep -v '^#' | grep -v '^$' | sed '/^$/d')
if [ -z "$SOFTS" ]; then
echo "错误: 未获取到列表或文件为空!请检查文件名(当前: $LIST_FILE)。" >&2
exit 1
fi
# 将列表转为数组
mapfile -t soft_array <<< "$SOFTS"
echo "检测到包管理器: $PM_NAME"
echo "开始使用 $PM_NAME 安装软件(命令: $BASE_CMD ... $EXTRA)"
echo "安装列表:"
printf '%s\n' "${soft_array[@]}"
echo "-----------------"
for soft in "${soft_array[@]}"; do
[ -z "$soft" ] && continue
echo "安装: $soft"
$BASE_CMD "$soft" $EXTRA || echo "警告: 安装 $soft 失败"
done
echo "-----------------"
echo "所有软件安装完成!"
}
main "$@"
| 1 | #!/usr/bin/env bash |
| 2 | |
| 3 | BASE_URL="https://gist.asfd.cn/jetsung/linux/raw/HEAD/" |
| 4 | LIST_FILE="apt.txt" # 默认列表文件(可被自动切换或 -n 覆盖) |
| 5 | DESC_FILE="README.md" # 描述 Markdown 文件 |
| 6 | EXTRA="" |
| 7 | VERBOSE=false # -v: 只显示详细信息,不安装 |
| 8 | |
| 9 | # 参数解析 |
| 10 | parameters() { |
| 11 | while getopts "e:n:v" opt; do |
| 12 | case $opt in |
| 13 | e) EXTRA="$OPTARG" ;; |
| 14 | n) LIST_FILE="$OPTARG" ;; |
| 15 | v) VERBOSE=true ;; |
| 16 | \?) echo "无效参数: -$OPTARG" >&2; exit 1 ;; |
| 17 | esac |
| 18 | done |
| 19 | shift $((OPTIND - 1)) |
| 20 | EXTRA="$EXTRA $@" |
| 21 | } |
| 22 | |
| 23 | # 检测包管理器并返回命令(如 "apt" 或 "dnf" 或 "yum") |
| 24 | detect_package_manager() { |
| 25 | if command -v apt >/dev/null 2>&1; then |
| 26 | echo "apt" |
| 27 | elif command -v dnf >/dev/null 2>&1; then |
| 28 | echo "dnf" |
| 29 | elif command -v yum >/dev/null 2>&1; then |
| 30 | echo "yum" |
| 31 | else |
| 32 | echo "none" |
| 33 | fi |
| 34 | } |
| 35 | |
| 36 | # 主函数 |
| 37 | main() { |
| 38 | parameters "$@" |
| 39 | |
| 40 | # 如果 LIST_FILE 没有扩展名,自动添加 .txt |
| 41 | if [[ "$LIST_FILE" != *.* ]]; then |
| 42 | LIST_FILE="${LIST_FILE}.txt" |
| 43 | fi |
| 44 | |
| 45 | URL_DESC="${BASE_URL}${DESC_FILE}" |
| 46 | |
| 47 | # -v 模式:解析 README.md 并显示软件详细信息 |
| 48 | if $VERBOSE; then |
| 49 | echo "从 $URL_DESC 获取软件描述信息..." |
| 50 | echo |
| 51 | curl -s --fail "$URL_DESC" | awk ' |
| 52 | /^\|.*\|.*\|.*\|.*\|$/ && NR > 2 { # 匹配数据行,跳过表头和分隔线 |
| 53 | gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "") # 去除行首尾空白 |
| 54 | split($0, fields, "|") |
| 55 | if (length(fields) < 5) next |
| 56 | |
| 57 | # 名称(第2列) |
| 58 | name_raw = fields[2] |
| 59 | gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", name_raw) |
| 60 | # 支持 [text](url) 或 **text** |
| 61 | if (match(name_raw, /\[([^]]+)\]/) || match(name_raw, /\*\*([^*]+)\*\*/)) { |
| 62 | name = substr(name_raw, RSTART + (substr(name_raw, RSTART, 1) == "[" ? 1 : 2), |
| 63 | RLENGTH - (substr(name_raw, RSTART, 1) == "[" ? 2 : 4)) |
| 64 | } else { |
| 65 | name = name_raw |
| 66 | } |
| 67 | |
| 68 | # apt ID(第3列,可能有 ` 或空) |
| 69 | apt_raw = fields[3] |
| 70 | gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", apt_raw) |
| 71 | gsub(/`/, "", apt_raw) |
| 72 | if (apt_raw == "") apt_raw = "(无)" |
| 73 | |
| 74 | # dnf ID(第4列,可能为空) |
| 75 | dnf_raw = fields[4] |
| 76 | gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", dnf_raw) |
| 77 | gsub(/`/, "", dnf_raw) |
| 78 | if (dnf_raw == "") dnf_raw = "(无)" |
| 79 | |
| 80 | # 描述(第5列) |
| 81 | desc = fields[5] |
| 82 | gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", desc) |
| 83 | |
| 84 | if (name == "" || desc == "") next |
| 85 | |
| 86 | printf "名称: %s\napt 包名: %s\ndnf 包名: %s\n描述: %s\n\n", name, apt_raw, dnf_raw, desc |
| 87 | }' |
| 88 | echo |
| 89 | exit 0 |
| 90 | fi |
| 91 | |
| 92 | # 正常模式:检测包管理器 |
| 93 | PM=$(detect_package_manager) |
| 94 | |
| 95 | case "$PM" in |
| 96 | apt) |
| 97 | BASE_CMD="sudo apt install -y" |
| 98 | PM_NAME="apt" |
| 99 | ;; |
| 100 | dnf) |
| 101 | BASE_CMD="sudo dnf install -y" |
| 102 | PM_NAME="dnf" |
| 103 | ;; |
| 104 | yum) |
| 105 | BASE_CMD="sudo yum install -y" |
| 106 | PM_NAME="yum" |
| 107 | ;; |
| 108 | none) |
| 109 | echo "错误: 未检测到支持的包管理器(apt、dnf 或 yum)!" >&2 |
| 110 | exit 1 |
| 111 | ;; |
| 112 | esac |
| 113 | |
| 114 | # 自动切换列表文件(如果检测到 dnf/yum 且存在 dnf.txt) |
| 115 | if [[ "$PM" == "dnf" || "$PM" == "yum" ]]; then |
| 116 | if [[ "$LIST_FILE" == "apt.txt" ]] && curl -s --head --fail "${BASE_URL}dnf.txt" >/dev/null; then |
| 117 | LIST_FILE="dnf.txt" |
| 118 | echo "检测到 $PM_NAME 系统,自动切换到 dnf.txt 列表文件。" |
| 119 | fi |
| 120 | fi |
| 121 | |
| 122 | URL_LIST="${BASE_URL}${LIST_FILE}" |
| 123 | echo "从 $URL_LIST 下载软件列表..." |
| 124 | SOFTS=$(curl -s --fail "$URL_LIST" | grep -v '^#' | grep -v '^$' | sed '/^$/d') |
| 125 | |
| 126 | if [ -z "$SOFTS" ]; then |
| 127 | echo "错误: 未获取到列表或文件为空!请检查文件名(当前: $LIST_FILE)。" >&2 |
| 128 | exit 1 |
| 129 | fi |
| 130 | |
| 131 | # 将列表转为数组 |
| 132 | mapfile -t soft_array <<< "$SOFTS" |
| 133 | |
| 134 | echo "检测到包管理器: $PM_NAME" |
| 135 | echo "开始使用 $PM_NAME 安装软件(命令: $BASE_CMD ... $EXTRA)" |
| 136 | echo "安装列表:" |
| 137 | printf '%s\n' "${soft_array[@]}" |
| 138 | echo "-----------------" |
| 139 | |
| 140 | for soft in "${soft_array[@]}"; do |
| 141 | [ -z "$soft" ] && continue |
| 142 | echo "安装: $soft" |
| 143 | $BASE_CMD "$soft" $EXTRA || echo "警告: 安装 $soft 失败" |
| 144 | done |
| 145 | |
| 146 | echo "-----------------" |
| 147 | echo "所有软件安装完成!" |
| 148 | } |
| 149 | |
| 150 | main "$@" |