Repository navigation
Expand file tree
/
Copy pathinstall.sh
More file actions
130 lines (114 loc) · 4.28 KB
/
Copy pathinstall.sh
File metadata and controls
130 lines (114 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/bin/sh
# ==============================================================================
# - 采用更安全的“下载到本地再执行”模式。
# - 自动清理临时文件。
# - 强制 Root 执行,并自动安装依赖。
# ==============================================================================
# --- 0. 清理机制 ---
# 使用 trap 命令,确保脚本在任何情况下退出时(正常结束、出错、被中断),
# 都能自动删除临时文件。临时文件名由 mktemp 随机生成,防止本地攻击者预建符号链接。
TMP_FILE=$(mktemp /tmp/install_payload.XXXXXX) || { echo "错误:无法创建临时文件。" >&2; exit 1; }
trap 'rm -f "$TMP_FILE"' EXIT
# --- 1. 权限检查 ---
if [ "$(id -u)" -ne 0 ]; then
echo "错误:此脚本必须以 root 用户身份运行。" >&2
exit 1
fi
# --- 2. 操作系统检测 ---
OS_FAMILY=""
if [ -f /etc/os-release ]; then
. /etc/os-release
OS_ID=$(echo "$ID" | tr '[:upper:]' '[:lower:]')
ID_LIKE=$(echo "$ID_LIKE" | tr '[:upper:]' '[:lower:]')
if echo "$ID_LIKE" | grep -q "debian" || [ "$OS_ID" = "debian" ] || [ "$OS_ID" = "ubuntu" ]; then
OS_FAMILY="debian"
elif echo "$ID_LIKE" | grep -q "rhel" || echo "$ID_LIKE" | grep -q "centos" || [ "$OS_ID" = "centos" ] || [ "$OS_ID" = "rhel" ] || [ "$OS_ID" = "fedora" ]; then
OS_FAMILY="rhel"
elif [ "$OS_ID" = "alpine" ]; then
OS_FAMILY="alpine"
fi
fi
if [ -z "$OS_FAMILY" ]; then
echo "错误:无法确定操作系统类型。" >&2; exit 1;
fi
# --- 3. 依赖自检与自动安装 ---
ensure_packages() {
for pkg in "$@"; do
if ! command -v "$pkg" >/dev/null 2>&1; then
echo "--> 未找到命令 '$pkg',正在尝试自动安装..."
case "$OS_FAMILY" in
debian) apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq "$pkg" ;;
rhel) if command -v dnf >/dev/null 2>&1; then dnf install -y "$pkg"; else yum install -y "$pkg"; fi ;;
alpine) apk add --no-cache "$pkg" ;;
esac
if ! command -v "$pkg" >/dev/null 2>&1; then
echo "错误:自动安装 '$pkg' 失败,请手动安装后重试。" >&2; exit 1;
else
echo "--> '$pkg' 安装成功。";
fi
fi
done
}
# --- 4. 执行主逻辑 ---
ensure_packages "curl"
DEBIAN_URL="https://raw.githubusercontent.com/txehq/snell.sh/main/snell.sh"
CENTOS_URL="https://snell-centos.jinqians.com"
ALPINE_URL="https://snell-docker.jinqians.com"
# 语法检查:优先用 bash -n(可解析 sh 语法),无 bash 时退回 sh -n
check_syntax() {
if command -v bash >/dev/null 2>&1; then
bash -n "$1"
else
sh -n "$1"
fi
}
main() {
url=$1
os_name=$2
shell_to_use=$3
echo "--------------------------------------------------"
echo "系统类型: $os_name"
echo "远程脚本: $url"
echo "操作模式: 下载脚本到 $TMP_FILE 后再执行"
echo "--------------------------------------------------"
printf "您确定要继续吗? [y/N]: "
read -r choice
case "$choice" in
y|Y)
echo "--> 正在下载脚本到 $TMP_FILE ..."
# 使用 -o 选项将内容输出到文件,-f 选项让 curl 在服务器出错时静默失败
if ! curl -sSL -f -o "$TMP_FILE" "$url"; then
echo "错误:下载脚本失败,请检查 URL 或网络连接。" >&2
# trap 会自动清理失败下载的空文件
exit 1
fi
# 完整性校验:文件非空 + 语法检查,不通过则丢弃并退出
if [ ! -s "$TMP_FILE" ]; then
echo "错误:下载的文件为空,已中止执行。" >&2
exit 1
fi
if ! check_syntax "$TMP_FILE" 2>/dev/null; then
echo "错误:下载的脚本未通过语法检查,已丢弃。" >&2
exit 1
fi
echo "--> 下载文件校验通过。"
echo "--> 下载完成。正在赋予执行权限..."
chmod +x "$TMP_FILE"
echo "--> 正在执行本地脚本 $TMP_FILE ..."
# 直接执行本地脚本
"$TMP_FILE"
echo "--> 本地脚本执行完毕。"
;;
*)
echo "--> 操作已取消。"
exit 0
;;
esac
}
case "$OS_FAMILY" in
debian) main "$DEBIAN_URL" "Debian/Ubuntu" "bash" ;;
rhel) main "$CENTOS_URL" "CentOS/RHEL" "bash" ;;
alpine) main "$ALPINE_URL" "Alpine" "sh" ;;
esac
# trap 会在脚本最后一步执行,清理文件
exit 0