#!/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 "$@"