v1.3.5 Performance: Optimize concurrent process execution to significantly accelerate script installation.

This commit is contained in:
fscarmen
2026-03-15 02:30:10 +00:00
parent f77b3ba2df
commit 623db9c416
2 changed files with 123 additions and 57 deletions
+7 -4
View File
@@ -24,16 +24,18 @@
* * * * * *
## 1.更新信息 ## 1.更新信息
2026.03.14 v1.3.5 Performance: Optimize concurrent process execution to significantly accelerate script installation. 性能优化:优化并发进程执行,大幅提升脚本安装速度
2026.02.08 v1.3.4 Chore: upgrade SS encryption method to SS-2022 spec; 新装的 Shadowsocks 协议加密方式从 aes-128-gcm 改为 2022-blake3-aes-128-gcm 2026.02.08 v1.3.4 Chore: upgrade SS encryption method to SS-2022 spec; 新装的 Shadowsocks 协议加密方式从 aes-128-gcm 改为 2022-blake3-aes-128-gcm
2026.01.20 v1.3.3 1. Security: In v2rayN, add pinnedPeerCertSha256 for Hysteria2/Trojan to prevent MITM (replaces AllowInsecure); 2. Compatibility: Refactor SFM/SFI/SFA configs for sing-box v1.13.0+; 1. 安全增强:v2rayN 的 Hysteria2/Trojan 支持 pinnedPeerCertSha256 替代 跳过证书验证,防御 MITM 攻击; 2. 适配更新:重构 SFM/SFI/SFA 配置,支持 sing-box v1.13.0+
2025.12.11 v1.3.2 Argo tunnel creation via API. Suitable for users with large-scale deployments, one Token for all. Automatically completed: Create tunnel > DNS configuration > Origin settings. Thanks to [zmlu] for providing the method: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh; Argo 隧道新增通过 API 创建,适合大量部署的用户,一个 Token 走天下。自动完成:创建隧道 > DNS 配置 > 回源设置。感谢热心网友 [zmlu] 提供的方法: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh
<details> <details>
<summary>历史更新 history(点击即可展开或收起)</summary> <summary>历史更新 history(点击即可展开或收起)</summary>
<br> <br>
>2026.01.20 v1.3.3 1. Security: In v2rayN, add pinnedPeerCertSha256 for Hysteria2/Trojan to prevent MITM (replaces AllowInsecure); 2. Compatibility: Refactor SFM/SFI/SFA configs for sing-box v1.13.0+; 1. 安全增强:v2rayN 的 Hysteria2/Trojan 支持 pinnedPeerCertSha256 替代 跳过证书验证,防御 MITM 攻击; 2. 适配更新:重构 SFM/SFI/SFA 配置,支持 sing-box v1.13.0+
>
>2025.12.11 v1.3.2 Argo tunnel creation via API. Suitable for users with large-scale deployments, one Token for all. Automatically completed: Create tunnel > DNS configuration > Origin settings. Thanks to [zmlu] for providing the method: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh; Argo 隧道新增通过 API 创建,适合大量部署的用户,一个 Token 走天下。自动完成:创建隧道 > DNS 配置 > 回源设置。感谢热心网友 [zmlu] 提供的方法: https://raw.githubusercontent.com/zmlu/sba/main/tunnel.sh
>
>2025.11.12 v1.3.1 1. Reality Configuration Update: In Reality configurations, the original multiplexing (multiplex) has been replaced with xtls-rprx-vision flow control, improving transmission efficiency, reducing latency, and enhancing security. The original configuration conversion script command remains fully compatible and unchanged — `bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh)`; 2. Quick Install Mode: Added a one-click installation feature that auto-fills all parameters, simplifying the deployment process. Chinese users can use -l or -L; English users can use -k or -K. Case-insensitive support makes operations more flexible; 3. Custom Reality Key Support: In response to user feedback, you can now specify a custom Reality private key via --REALITY_PRIVATE=<privateKey>. The script will automatically compute the corresponding public key using the integrated API. If left blank, it generates a random private-public key pair in real-time; 4. Enhanced HTTP + Reality Support in Clash Clients: Added full compatibility for HTTP + Reality transport in Clash clients, improving connection stability and performance; 1. Reality 配置变更:在 Reality 配置中,将原来的多路复用(multiplex)替换为 xtls-rprx-vision 流控,提升传输效率、降低延迟并增强安全性。原配置转换脚本命令—— `bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh)` ; 2. 极速安装模式:新增一键安装功能,所有参数自动填充,简化部署流程。中文用户使用 -l 或 -L,英文用户使用 -k 或 -K,大小写均支持,操作更灵; 3. 自定义 Reality 密钥支持:响应用户反馈,现支持通过 --REALITY_PRIVATE=<privateKey> 指定自定义 Reality 私钥,脚本将调用相关 API 自动计算对应公钥。若留空,则实时生成随机公私钥; 4. HTTP + Reality 在 Clash 客户端的增强支持:补充了对 Clash 客户端中 HTTP + Reality 传输方式的完整兼容,提升了连接稳定性和性能 >2025.11.12 v1.3.1 1. Reality Configuration Update: In Reality configurations, the original multiplexing (multiplex) has been replaced with xtls-rprx-vision flow control, improving transmission efficiency, reducing latency, and enhancing security. The original configuration conversion script command remains fully compatible and unchanged — `bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh)`; 2. Quick Install Mode: Added a one-click installation feature that auto-fills all parameters, simplifying the deployment process. Chinese users can use -l or -L; English users can use -k or -K. Case-insensitive support makes operations more flexible; 3. Custom Reality Key Support: In response to user feedback, you can now specify a custom Reality private key via --REALITY_PRIVATE=<privateKey>. The script will automatically compute the corresponding public key using the integrated API. If left blank, it generates a random private-public key pair in real-time; 4. Enhanced HTTP + Reality Support in Clash Clients: Added full compatibility for HTTP + Reality transport in Clash clients, improving connection stability and performance; 1. Reality 配置变更:在 Reality 配置中,将原来的多路复用(multiplex)替换为 xtls-rprx-vision 流控,提升传输效率、降低延迟并增强安全性。原配置转换脚本命令—— `bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh)` ; 2. 极速安装模式:新增一键安装功能,所有参数自动填充,简化部署流程。中文用户使用 -l 或 -L,英文用户使用 -k 或 -K,大小写均支持,操作更灵; 3. 自定义 Reality 密钥支持:响应用户反馈,现支持通过 --REALITY_PRIVATE=<privateKey> 指定自定义 Reality 私钥,脚本将调用相关 API 自动计算对应公钥。若留空,则实时生成随机公私钥; 4. HTTP + Reality 在 Clash 客户端的增强支持:补充了对 Clash 客户端中 HTTP + Reality 传输方式的完整兼容,提升了连接稳定性和性能
> >
>2025.11.10 v1.3.0 Replace multiplex with xtls-rprx-vision flow control in reality configuration. The original configuration conversion script: bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh); 在 reality 配置中将多路复用 multiplex 替换为 xtls-rprx-vision 流控。原来的配置转换脚本: bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh) >2025.11.10 v1.3.0 Replace multiplex with xtls-rprx-vision flow control in reality configuration. The original configuration conversion script: bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh); 在 reality 配置中将多路复用 multiplex 替换为 xtls-rprx-vision 流控。原来的配置转换脚本: bash <(curl -sSL https://raw.githubusercontent.com/fscarmen/tools/main/vision.sh)
@@ -695,6 +697,7 @@ SharonNetworks 为您的业务起飞保驾护航!
* 坚如磐石的数据中心。高枕无忧 * 坚如磐石的数据中心。高枕无忧
## 15.免责声明 ## 15.免责声明
* 本程序仅供学习了解, 非盈利目的,请于下载后 24 小时内删除, 不得用作任何商业用途, 文字、数据及图片均有所属版权, 如转载须注明来源。 * 本程序仅供学习了解, 非盈利目的,请于下载后 24 小时内删除, 不得用作任何商业用途, 文字、数据及图片均有所属版权, 如转载须注明来源。
* 使用本程序必循遵守部署免责声明。使用本程序必循遵守部署服务器所在地、所在国家和用户所在国家的法律法规, 程序作者不对使用者任何不当行为负责。 * 使用本程序必循遵守部署免责声明。使用本程序必循遵守部署服务器所在地、所在国家和用户所在国家的法律法规, 程序作者不对使用者任何不当行为负责。
+112 -49
View File
@@ -1,10 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# 当前脚本版本号 # 当前脚本版本号
VERSION='v1.3.4 (2026.02.08)' VERSION='v1.3.5 (2026.03.14)'
# Github 反代加速代理,第一个为空相当于直连 # Github 反代加速代理
GITHUB_PROXY=('' 'https://v6.gh-proxy.org/' 'https://gh-proxy.com/' 'https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/' 'https://ghproxy.lvedong.eu.org/') GITHUB_PROXY=('https://v6.gh-proxy.org/' 'https://gh-proxy.com/' 'https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/' 'https://ghproxy.lvedong.eu.org/')
# 各变量默认值 # 各变量默认值
TEMP_DIR='/tmp/sing-box' TEMP_DIR='/tmp/sing-box'
@@ -24,14 +24,14 @@ DEFAULT_NEWEST_VERSION='1.13.0-rc.4'
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
trap "rm -rf $TEMP_DIR >/dev/null 2>&1 ; echo -e '\n' ;exit" INT QUIT TERM EXIT trap "wait 2>/dev/null; rm -rf $TEMP_DIR >/dev/null 2>&1; echo -e '\n'; exit" INT QUIT TERM EXIT
mkdir -p $TEMP_DIR mkdir -p $TEMP_DIR
E[0]="Language:\n 1. English (default) \n 2. 简体中文" E[0]="Language:\n 1. English (default) \n 2. 简体中文"
C[0]="${E[0]}" C[0]="${E[0]}"
E[1]="1. Chore: upgrade SS encryption method to SS-2022 spec 2. Security: Add pinnedPeerCertSha256 for Hysteria2/Trojan in v2rayN to prevent MITM (replaces AllowInsecure); 3. Compatibility: Refactor SFM/SFI/SFA configs for sing-box v1.13.0+." E[1]="1. Chore: upgrade SS encryption method to SS-2022 spec; 2. Security: Add pinnedPeerCertSha256 for Hysteria2/Trojan in v2rayN to prevent MITM (replaces AllowInsecure); 3. Compatibility: Refactor SFM/SFI/SFA configs for sing-box v1.13.0+; 4. Performance: Optimize concurrent process execution to significantly accelerate script installation."
C[1]="1. 新装的 Shadowsocks 协议加密方式从 aes-128-gcm 改为 2022-blake3-aes-128-gcm; 2. 安全增强:v2rayN 的 Hysteria2/Trojan 支持 pinnedPeerCertSha256 替代 跳过证书验证,防御 MITM 攻击; 3. 适配更新:重构 SFM/SFI/SFA 配置,支持 sing-box v1.13.0+" C[1]="1. 新装的 Shadowsocks 协议加密方式从 aes-128-gcm 改为 2022-blake3-aes-128-gcm; 2. 安全增强:v2rayN 的 Hysteria2/Trojan 支持 pinnedPeerCertSha256 替代 跳过证书验证,防御 MITM 攻击; 3. 适配更新:重构 SFM/SFI/SFA 配置,支持 sing-box v1.13.0+; 4. 性能优化:优化并发进程执行,大幅提升脚本安装速度。"
E[2]="Downloading Sing-box. Please wait a seconds ..." E[2]="Downloading Sing-box. Please wait a seconds ..."
C[2]="下载 Sing-box 中,请稍等 ..." C[2]="下载 Sing-box 中,请稍等 ..."
E[3]="Input errors up to 5 times.The script is aborted." E[3]="Input errors up to 5 times.The script is aborted."
@@ -293,11 +293,25 @@ text() { grep -q '\$' <<< "${E[$*]}" && eval echo "\$(eval echo "\${${L}[$*]}")"
# 检测是否需要启用 Github CDN,如能直接连通,则不使用 # 检测是否需要启用 Github CDN,如能直接连通,则不使用
check_cdn() { check_cdn() {
# GITHUB_PROXY 数组第一个元素为空,相当于直连 local PROXY
for PROXY_URL in "${GITHUB_PROXY[@]}"; do
local PROXY_STATUS_CODE=$(wget --server-response --spider --quiet --timeout=3 --tries=1 ${PROXY_URL}https://api.github.com/repos/SagerNet/sing-box/releases 2>&1 | awk '/HTTP\//{last_field = $2} END {print last_field}') for PROXY in "" "${GITHUB_PROXY[@]}"; do
[ "$PROXY_STATUS_CODE" = "200" ] && GH_PROXY="$PROXY_URL" && break {
local CODE=$(wget -qT3 --spider --server-response "${PROXY}https://raw.githubusercontent.com/" 2>&1 | awk '/HTTP\//{code=$2} END{print code}')
[ "$CODE" = "200" ] && [ ! -s "${TEMP_DIR}/cdn_proxy" ] && echo "$PROXY" > "${TEMP_DIR}/cdn_proxy"
} &
done done
# 等第一个成功
while [ ! -s "${TEMP_DIR}/cdn_proxy" ]; do
sleep 0.05
done
GH_PROXY=$(cat "${TEMP_DIR}/cdn_proxy")
# 清理后台任务和临时文件
rm -rf "${TEMP_DIR}/cdn_proxy"
wait 2>/dev/null
} }
# 检测是否解锁 chatGPT,以决定是否使用 warp 链式代理或者是 direct out,此处判断改编自 https://github.com/lmc999/RegionRestrictionCheck # 检测是否解锁 chatGPT,以决定是否使用 warp 链式代理或者是 direct out,此处判断改编自 https://github.com/lmc999/RegionRestrictionCheck
@@ -332,7 +346,7 @@ check_chatgpt() {
} }
# 脚本当天及累计运行次数统计 # 脚本当天及累计运行次数统计
statistics_of_run-times() { statistics_of_run_times() {
local UPDATE_OR_GET=$1 local UPDATE_OR_GET=$1
local SCRIPT=$2 local SCRIPT=$2
if grep -q 'update' <<< "$UPDATE_OR_GET"; then if grep -q 'update' <<< "$UPDATE_OR_GET"; then
@@ -358,7 +372,7 @@ select_language() {
# 字母与数字的 ASCII 码值转换 # 字母与数字的 ASCII 码值转换
asc() { asc() {
if [[ "$1" = [a-z] ]]; then if [[ "$1" = [a-z] ]]; then
[ "$2" = '++' ] && printf "\\$(printf '%03o' "$[ $(printf "%d" "'$1'") + 1 ]")" || printf "%d" "'$1'" [ "$2" = '++' ] && printf "\\$(printf '%03o' "$(( $(printf "%d" "'$1'") + 1 ))")" || printf "%d" "'$1'"
else else
[[ "$1" =~ ^[0-9]+$ ]] && printf "\\$(printf '%03o' "$1")" [[ "$1" =~ ^[0-9]+$ ]] && printf "\\$(printf '%03o' "$1")"
fi fi
@@ -368,7 +382,7 @@ asc() {
input_cdn() { input_cdn() {
echo "" echo ""
for c in "${!CDN_DOMAIN[@]}"; do for c in "${!CDN_DOMAIN[@]}"; do
hint " $[c+1]. ${CDN_DOMAIN[c]} " hint " $(( c+1 )). ${CDN_DOMAIN[c]} "
done done
reading "\n $(text 53) " CUSTOM_CDN reading "\n $(text 53) " CUSTOM_CDN
@@ -395,7 +409,7 @@ change_cdn() {
# 提示当前使用的 CDN 并让用户选择或输入新的 CDN # 提示当前使用的 CDN 并让用户选择或输入新的 CDN
hint "\n $(text 109) \n" hint "\n $(text 109) \n"
for ((c=0; c<${#CDN_DOMAIN[@]}; c++)); do for ((c=0; c<${#CDN_DOMAIN[@]}; c++)); do
hint " $[c+1]. ${CDN_DOMAIN[c]} " hint " $(( c+1 )). ${CDN_DOMAIN[c]} "
done done
reading "\n $(text 111) " CDN_CHOOSE reading "\n $(text 111) " CDN_CHOOSE
@@ -647,9 +661,9 @@ input_hopping_port() {
PORT_HOPPING_RANGE=${PORT_HOPPING_RANGE//-/:} PORT_HOPPING_RANGE=${PORT_HOPPING_RANGE//-/:}
PORT_HOPPING_START=${PORT_HOPPING_RANGE%:*} PORT_HOPPING_START=${PORT_HOPPING_RANGE%:*}
PORT_HOPPING_END=${PORT_HOPPING_RANGE#*:} PORT_HOPPING_END=${PORT_HOPPING_RANGE#*:}
[[ "$PORT_HOPPING_START" < "$PORT_HOPPING_END" && "$PORT_HOPPING_START" -ge "$MIN_HOPPING_PORT" && "$PORT_HOPPING_END" -le "$MAX_HOPPING_PORT" ]] && IS_HOPPING=is_hopping || warning "\n $(text 36) " [[ "$PORT_HOPPING_START" -lt "$PORT_HOPPING_END" && "$PORT_HOPPING_START" -ge "$MIN_HOPPING_PORT" && "$PORT_HOPPING_END" -le "$MAX_HOPPING_PORT" ]] && IS_HOPPING=is_hopping || warning "\n $(text 36) "
elif [[ -z "$PORT_HOPPING_RANGE" || "${PORT_HOPPING_RANGE,,}" =~ ^(n|no)$ ]]; then elif [[ -z "$PORT_HOPPING_RANGE" || "${PORT_HOPPING_RANGE,,}" =~ ^(n|no)$ ]]; then
IS_HOPPING=no_hoppinng IS_HOPPING=no_hopping
else else
warning "\n $(text 36) " warning "\n $(text 36) "
fi fi
@@ -691,7 +705,7 @@ input_argo_auth() {
ARGO_DOMAIN=$(sed 's/[ ]*//g; s/:[ ]*//' <<< "$ARGO_DOMAIN") ARGO_DOMAIN=$(sed 's/[ ]*//g; s/:[ ]*//' <<< "$ARGO_DOMAIN")
fi fi
if [[ -z "$ARGO_DOMAIN" && ( "$ARGO_DOMAIN" =~ trycloudflare\.com$ || "$IS_CHANGE_ARGO" = 'is_add_protocols' || "$IS_CHANGE_ARGO" = 'is_install' || "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ) ]]; then if [[ ( -z "$ARGO_DOMAIN" || "$ARGO_DOMAIN" =~ trycloudflare\.com$ ) && ( "$IS_CHANGE_ARGO" = 'is_add_protocols' || "$IS_CHANGE_ARGO" = 'is_install' || "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ) ]]; then
ARGO_RUNS="${WORK_DIR}/cloudflared tunnel --edge-ip-version auto --no-autoupdate --url http://localhost:$PORT_NGINX" ARGO_RUNS="${WORK_DIR}/cloudflared tunnel --edge-ip-version auto --no-autoupdate --url http://localhost:$PORT_NGINX"
elif [ -n "${ARGO_DOMAIN}" ]; then elif [ -n "${ARGO_DOMAIN}" ]; then
if [ -z "${ARGO_AUTH}" ]; then if [ -z "${ARGO_AUTH}" ]; then
@@ -859,7 +873,7 @@ check_install() {
if [ -s ${SINGBOX_DAEMON_FILE} ]; then if [ -s ${SINGBOX_DAEMON_FILE} ]; then
SYSTEMD_EXECSTART=$(grep '^ExecStart=' ${SINGBOX_DAEMON_FILE}) SYSTEMD_EXECSTART=$(grep '^ExecStart=' ${SINGBOX_DAEMON_FILE})
case "$SYSTEMD_EXECSTART" in case "$SYSTEMD_EXECSTART" in
'ExecStart=/etc/sing-box/sing-box run -C /etc/sing-box/conf/' | 'ExecStart=/etc/sing-box/sing-box run -C /etc/sing-box/conf' ) "ExecStart=${WORK_DIR}/sing-box run -C ${WORK_DIR}/conf/" | "ExecStart=${WORK_DIR}/sing-box run -C ${WORK_DIR}/conf" )
[ "$(systemctl is-active sing-box)" = 'active' ] && STATUS[0]=$(text 28) || STATUS[0]=$(text 27) [ "$(systemctl is-active sing-box)" = 'active' ] && STATUS[0]=$(text 28) || STATUS[0]=$(text 27)
;; ;;
'ExecStart=/etc/v2ray-agent/sing-box/sing-box run -c /etc/v2ray-agent/sing-box/conf/config.json' ) 'ExecStart=/etc/v2ray-agent/sing-box/sing-box run -c /etc/v2ray-agent/sing-box/conf/config.json' )
@@ -876,7 +890,7 @@ check_install() {
;; ;;
* ) * )
# 检查是否是自己的脚本安装的,但路径略有不同 # 检查是否是自己的脚本安装的,但路径略有不同
if [[ "$SYSTEMD_EXECSTART" =~ "ExecStart=/etc/sing-box/sing-box run" ]]; then if [[ "$SYSTEMD_EXECSTART" =~ "ExecStart=${WORK_DIR}/sing-box run" ]]; then
[ "$(systemctl is-active sing-box)" = 'active' ] && STATUS[0]=$(text 28) || STATUS[0]=$(text 27) [ "$(systemctl is-active sing-box)" = 'active' ] && STATUS[0]=$(text 28) || STATUS[0]=$(text 27)
else else
SING_BOX_SCRIPT='Unknown or customized sing-box' && error "\n $(text 99) \n" SING_BOX_SCRIPT='Unknown or customized sing-box' && error "\n $(text 99) \n"
@@ -890,7 +904,7 @@ check_install() {
;; ;;
* ) * )
# 检查是否是自己的脚本安装的,但路径略有不同 # 检查是否是自己的脚本安装的,但路径略有不同
if [[ "$SYSTEMD_EXECSTART" =~ "ExecStart=/etc/sing-box/sing-box run" ]]; then if [[ "$SYSTEMD_EXECSTART" =~ "ExecStart=${WORK_DIR}/sing-box run" ]]; then
[ "$(systemctl is-active sing-box)" = 'active' ] && STATUS[0]=$(text 28) || STATUS[0]=$(text 27) [ "$(systemctl is-active sing-box)" = 'active' ] && STATUS[0]=$(text 28) || STATUS[0]=$(text 27)
else else
SING_BOX_SCRIPT='Unknown or customized sing-box' && error "\n $(text 99) \n" SING_BOX_SCRIPT='Unknown or customized sing-box' && error "\n $(text 99) \n"
@@ -901,16 +915,41 @@ check_install() {
fi fi
fi fi
# 并发下载订阅模板 (clash, clash2, sing-box),在新安装和更换协议时会用到
{
wget --no-check-certificate --continue -qO $TEMP_DIR/clash ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash 2>/dev/null &
wget --no-check-certificate --continue -qO $TEMP_DIR/clash2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash2 2>/dev/null &
wget --no-check-certificate --continue -qO $TEMP_DIR/sing-box ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/sing-box 2>/dev/null &
wait
} &
# 如果有需要,后台静默下载 sing-box # 如果有需要,后台静默下载 sing-box
if [ "${STATUS[0]}" = "$(text 26)" ] && [ ! -s ${WORK_DIR}/sing-box ]; then if [ "${STATUS[0]}" = "$(text 26)" ] && [ ! -s ${WORK_DIR}/sing-box ]; then
# 任务1: 下载 sing-box
{ {
# 获取需要下载的 sing-box 版本
local ONLINE=$(get_sing_box_version) local ONLINE=$(get_sing_box_version)
wget --no-check-certificate --continue ${GH_PROXY}https://github.com/SagerNet/sing-box/releases/download/v$ONLINE/sing-box-$ONLINE-linux-$SING_BOX_ARCH.tar.gz -qO- | tar xz -C $TEMP_DIR sing-box-$ONLINE-linux-$SING_BOX_ARCH/sing-box >/dev/null 2>&1 local SB_DIR="$TEMP_DIR/sing-box-$ONLINE-linux-$SING_BOX_ARCH"
[ -s $TEMP_DIR/sing-box-$ONLINE-linux-$SING_BOX_ARCH/sing-box ] && mv $TEMP_DIR/sing-box-$ONLINE-linux-$SING_BOX_ARCH/sing-box $TEMP_DIR local SB_BIN="$SB_DIR/sing-box"
wget --no-check-certificate --continue -qO $TEMP_DIR/jq ${GH_PROXY}https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-$JQ_ARCH >/dev/null 2>&1 && chmod +x $TEMP_DIR/jq >/dev/null 2>&1 wget --no-check-certificate --continue \
wget --no-check-certificate --continue -qO $TEMP_DIR/qrencode ${GH_PROXY}https://github.com/fscarmen/client_template/raw/main/qrencode-go/qrencode-go-linux-$QRENCODE_ARCH >/dev/null 2>&1 && chmod +x $TEMP_DIR/qrencode >/dev/null 2>&1 ${GH_PROXY}https://github.com/SagerNet/sing-box/releases/download/v$ONLINE/sing-box-$ONLINE-linux-$SING_BOX_ARCH.tar.gz \
-qO- | tar xz -C $TEMP_DIR 2>/dev/null
[ -s "$SB_BIN" ] && [ -x "$SB_BIN" ] && mv "$SB_BIN" "$TEMP_DIR/sing-box"
} & } &
# 任务2: 下载 jq
{
wget --no-check-certificate --continue -qO $TEMP_DIR/jq \
${GH_PROXY}https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-$JQ_ARCH 2>/dev/null \
&& chmod +x $TEMP_DIR/jq
} &
# 任务3: 下载 qrencode
{
wget --no-check-certificate --continue -qO $TEMP_DIR/qrencode \
${GH_PROXY}https://github.com/fscarmen/client_template/raw/main/qrencode-go/qrencode-go-linux-$QRENCODE_ARCH 2>/dev/null \
&& chmod +x $TEMP_DIR/qrencode
} &
elif [ "${STATUS[0]}" != "$(text 26)" ]; then elif [ "${STATUS[0]}" != "$(text 26)" ]; then
# 查 sing-box 进程号,运行时长和内存占用,占用的端口 # 查 sing-box 进程号,运行时长和内存占用,占用的端口
SING_BOX_VERSION="Version: $(${WORK_DIR}/sing-box version | awk '/version/{print $NF}')" SING_BOX_VERSION="Version: $(${WORK_DIR}/sing-box version | awk '/version/{print $NF}')"
@@ -1208,17 +1247,34 @@ check_system_ip() {
[ -n "$DEFAULT_LOCAL_IP6" ] && local BIND_ADDRESS6="--bind-address=$DEFAULT_LOCAL_IP6" [ -n "$DEFAULT_LOCAL_IP6" ] && local BIND_ADDRESS6="--bind-address=$DEFAULT_LOCAL_IP6"
fi fi
local IP4_JSON=$(wget $BIND_ADDRESS4 -4 -qO- --no-check-certificate --tries=2 --timeout=2 https://ip.cloudflare.now.cc${IS_CHINESE}) && # 并行检测 IPv4 和 IPv6 信息
{
local CHECK_IP4=$(wget $BIND_ADDRESS4 -4 -qO- --no-check-certificate --tries=2 --timeout=2 https://ip.cloudflare.now.cc${IS_CHINESE})
grep -q '.' <<< "$CHECK_IP4" && echo "$CHECK_IP4" > $TEMP_DIR/ip4.json
}&
{
local CHECK_IP6=$(wget $BIND_ADDRESS6 -6 -qO- --no-check-certificate --tries=2 --timeout=2 https://ip.cloudflare.now.cc${IS_CHINESE})
grep -q '.' <<< "$CHECK_IP6" && echo "$CHECK_IP6" > $TEMP_DIR/ip6.json
}&
wait
[ -s $TEMP_DIR/ip4.json ] &&
local IP4_JSON=$(cat $TEMP_DIR/ip4.json) &&
WAN4=$(awk -F '"' '/"ip"/{print $4}' <<< "$IP4_JSON") && WAN4=$(awk -F '"' '/"ip"/{print $4}' <<< "$IP4_JSON") &&
COUNTRY4=$(awk -F '"' '/"country"/{print $4}' <<< "$IP4_JSON") && COUNTRY4=$(awk -F '"' '/"country"/{print $4}' <<< "$IP4_JSON") &&
EMOJI4=$(awk -F '"' '/"emoji"/{print $4}' <<< "$IP4_JSON") && EMOJI4=$(awk -F '"' '/"emoji"/{print $4}' <<< "$IP4_JSON") &&
ASNORG4=$(awk -F '"' '/"isp"/{print $4}' <<< "$IP4_JSON") ASNORG4=$(awk -F '"' '/"isp"/{print $4}' <<< "$IP4_JSON") &&
rm -f $TEMP_DIR/ip4.json
local IP6_JSON=$(wget $BIND_ADDRESS6 -6 -qO- --no-check-certificate --tries=2 --timeout=2 https://ip.cloudflare.now.cc${IS_CHINESE}) && [ -s $TEMP_DIR/ip6.json ] &&
local IP6_JSON=$(cat $TEMP_DIR/ip6.json) &&
WAN6=$(awk -F '"' '/"ip"/{print $4}' <<< "$IP6_JSON") && WAN6=$(awk -F '"' '/"ip"/{print $4}' <<< "$IP6_JSON") &&
COUNTRY6=$(awk -F '"' '/"country"/{print $4}' <<< "$IP6_JSON") && COUNTRY6=$(awk -F '"' '/"country"/{print $4}' <<< "$IP6_JSON") &&
EMOJI6=$(awk -F '"' '/"emoji"/{print $4}' <<< "$IP6_JSON") && EMOJI6=$(awk -F '"' '/"emoji"/{print $4}' <<< "$IP6_JSON") &&
ASNORG6=$(awk -F '"' '/"isp"/{print $4}' <<< "$IP6_JSON") ASNORG6=$(awk -F '"' '/"isp"/{print $4}' <<< "$IP6_JSON") &&
rm -f $TEMP_DIR/ip6.json
} }
# 输入起始 port 函数 # 输入起始 port 函数
@@ -1265,11 +1321,11 @@ sing-box_variables() {
fi fi
# 选择安装的协议,由于选项 a 为全部协议,所以选项数不是从 a 开始,而是从 b 开始,处理输入:把大写全部变为小写,把不符合的选项去掉,把重复的选项合并 # 选择安装的协议,由于选项 a 为全部协议,所以选项数不是从 a 开始,而是从 b 开始,处理输入:把大写全部变为小写,把不符合的选项去掉,把重复的选项合并
MAX_CHOOSE_PROTOCOLS=$(asc $[CONSECUTIVE_PORTS+96+1]) MAX_CHOOSE_PROTOCOLS=$(asc $(( CONSECUTIVE_PORTS+96+1 )))
if [ -z "$CHOOSE_PROTOCOLS" ]; then if [ -z "$CHOOSE_PROTOCOLS" ]; then
hint "\n (1/6) $(text 49) " hint "\n (1/6) $(text 49) "
for e in "${!PROTOCOL_LIST[@]}"; do for e in "${!PROTOCOL_LIST[@]}"; do
[[ "$e" =~ '6'|'7' ]] && hint " $(asc $[e+98]). ${PROTOCOL_LIST[e]} " || hint " $(asc $[e+98]). ${PROTOCOL_LIST[e]} " hint " $(asc $(( e+98 ))). ${PROTOCOL_LIST[e]} "
done done
reading "\n $(text 24) " CHOOSE_PROTOCOLS reading "\n $(text 24) " CHOOSE_PROTOCOLS
fi fi
@@ -1281,7 +1337,7 @@ sing-box_variables() {
if [ -z "$START_PORT" ]; then if [ -z "$START_PORT" ]; then
hint "\n $(text 60) " hint "\n $(text 60) "
for w in "${!INSTALL_PROTOCOLS[@]}"; do for w in "${!INSTALL_PROTOCOLS[@]}"; do
[ "$w" -ge 9 ] && hint " $[w+1]. ${PROTOCOL_LIST[$(($(asc ${INSTALL_PROTOCOLS[w]}) - 98))]} " || hint " $[w+1] . ${PROTOCOL_LIST[$(($(asc ${INSTALL_PROTOCOLS[w]}) - 98))]} " [ "$w" -ge 9 ] && hint " $(( w+1 )). ${PROTOCOL_LIST[$(($(asc ${INSTALL_PROTOCOLS[w]}) - 98))]} " || hint " $(( w+1 )) . ${PROTOCOL_LIST[$(($(asc ${INSTALL_PROTOCOLS[w]}) - 98))]} "
done done
input_start_port ${#INSTALL_PROTOCOLS[@]} input_start_port ${#INSTALL_PROTOCOLS[@]}
fi fi
@@ -1881,7 +1937,7 @@ EOF
# 第1个协议为 b (a为全部),生成 XTLS + Reality 配置 # 第1个协议为 b (a为全部),生成 XTLS + Reality 配置
CHECK_PROTOCOLS=b CHECK_PROTOCOLS=b
if [[ "${INSTALL_PROTOCOLS[@]}" =~ "$CHECK_PROTOCOLS" ]]; then if [[ "${INSTALL_PROTOCOLS[@]}" =~ "$CHECK_PROTOCOLS" ]]; then
[ -z "$PORT_XTLS_REALITY" ] && PORT_XTLS_REALITY=$[START_PORT+$(awk -v target=$CHECK_PROTOCOLS '{ for(i=1; i<=NF; i++) if($i == target) { print i-1; break } }' <<< "${INSTALL_PROTOCOLS[*]}")] [ -z "$PORT_XTLS_REALITY" ] && PORT_XTLS_REALITY=$(( START_PORT+$(awk -v target=$CHECK_PROTOCOLS '{ for(i=1; i<=NF; i++) if($i == target) { print i-1; break } }' <<< "${INSTALL_PROTOCOLS[*]}") ))
NODE_NAME[11]=${NODE_NAME[11]:-"$NODE_NAME_CONFIRM"} && UUID[11]=${UUID[11]:-"$UUID_CONFIRM"} && TLS_SERVER[11]=${TLS_SERVER[11]:-"$TLS_SERVER"} && REALITY_PRIVATE[11]=${REALITY_PRIVATE[11]:-"$REALITY_PRIVATE"} && REALITY_PUBLIC[11]=${REALITY_PUBLIC[11]:-"$REALITY_PUBLIC"} && NODE_NAME[11]=${NODE_NAME[11]:-"$NODE_NAME_CONFIRM"} && UUID[11]=${UUID[11]:-"$UUID_CONFIRM"} && TLS_SERVER[11]=${TLS_SERVER[11]:-"$TLS_SERVER"} && REALITY_PRIVATE[11]=${REALITY_PRIVATE[11]:-"$REALITY_PRIVATE"} && REALITY_PUBLIC[11]=${REALITY_PUBLIC[11]:-"$REALITY_PUBLIC"} &&
cat > ${WORK_DIR}/conf/11_${NODE_TAG[0]}_inbounds.json << EOF cat > ${WORK_DIR}/conf/11_${NODE_TAG[0]}_inbounds.json << EOF
// "public_key":"${REALITY_PUBLIC[11]}" // "public_key":"${REALITY_PUBLIC[11]}"
@@ -2567,8 +2623,13 @@ fetch_quicktunnel_domain() {
local CLOUDFLARED_PID=$(ps -eo pid,args | awk -v work_dir="$WORK_DIR" '$0~(work_dir"/cloudflared"){print $1;exit}') local CLOUDFLARED_PID=$(ps -eo pid,args | awk -v work_dir="$WORK_DIR" '$0~(work_dir"/cloudflared"){print $1;exit}')
[[ -z "$METRICS_ADDRESS" && "$CLOUDFLARED_PID" =~ ^[0-9]+$ ]] && local METRICS_ADDRESS=$(ss -nltp | grep "pid=$CLOUDFLARED_PID" | awk '{print $4}') [[ -z "$METRICS_ADDRESS" && "$CLOUDFLARED_PID" =~ ^[0-9]+$ ]] && local METRICS_ADDRESS=$(ss -nltp | grep "pid=$CLOUDFLARED_PID" | awk '{print $4}')
[ -n "$METRICS_ADDRESS" ] && ARGO_DOMAIN=$(wget -qO- http://$METRICS_ADDRESS/quicktunnel | awk -F '"' '{print $4}') [ -n "$METRICS_ADDRESS" ] && ARGO_DOMAIN=$(wget -qO- http://$METRICS_ADDRESS/quicktunnel | awk -F '"' '{print $4}')
[[ ! "$ARGO_DOMAIN" =~ trycloudflare\.com$ ]] && (( QUICKTUNNEL_ERROR_TIME-- )) && sleep 2 || break if [[ ! "$ARGO_DOMAIN" =~ trycloudflare\.com$ ]]; then
(( QUICKTUNNEL_ERROR_TIME-- )) || true
[ "$QUICKTUNNEL_ERROR_TIME" = '0' ] && error " $(text 93) " [ "$QUICKTUNNEL_ERROR_TIME" = '0' ] && error " $(text 93) "
sleep 2
else
break
fi
done done
# 把临时隧道写到 Sing-box 相应的 ws inbounds 文件 # 把临时隧道写到 Sing-box 相应的 ws inbounds 文件
@@ -2771,18 +2832,20 @@ export_list() {
# 后台生成 clash 订阅配置文件 # 后台生成 clash 订阅配置文件
{ {
# 模板1: 使用 proxy providers # 模板1: 使用 proxy providers
wget --no-check-certificate -qO- --tries=3 --timeout=2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash | sed "s#NODE_NAME#${NODE_NAME_CONFIRM}#g; s#PROXY_PROVIDERS_URL#$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/proxies#" > ${WORK_DIR}/subscribe/clash cat ${TEMP_DIR}/clash | sed "s#NODE_NAME#${NODE_NAME_CONFIRM}#g; s#PROXY_PROVIDERS_URL#$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/proxies#" > ${WORK_DIR}/subscribe/clash
# 模板2: 不使用 proxy providers # 模板2: 不使用 proxy providers
CLASH2_PORT=("$PORT_XTLS_REALITY" "$PORT_HYSTERIA2" "$PORT_TUIC" "$PORT_SHADOWTLS" "$PORT_SHADOWSOCKS" "$PORT_TROJAN" "$PORT_VMESS_WS" "$PORT_VLESS_WS" "$PORT_GRPC_REALITY" "$PORT_ANYTLS") CLASH2_PORT=("$PORT_XTLS_REALITY" "$PORT_HYSTERIA2" "$PORT_TUIC" "$PORT_SHADOWTLS" "$PORT_SHADOWSOCKS" "$PORT_TROJAN" "$PORT_VMESS_WS" "$PORT_VLESS_WS" "$PORT_GRPC_REALITY" "$PORT_ANYTLS")
CLASH2_PROXY_INSERT=("$CLASH_XTLS_REALITY" "$CLASH_HYSTERIA2" "$CLASH_TUIC" "$CLASH_SHADOWTLS" "$CLASH_SHADOWSOCKS" "$CLASH_TROJAN" "$CLASH_VMESS_WS" "$CLASH_VLESS_WS" "$CLASH_GRPC_REALITY" "$CLASH_ANYTLS") CLASH2_PROXY_INSERT=("$CLASH_XTLS_REALITY" "$CLASH_HYSTERIA2" "$CLASH_TUIC" "$CLASH_SHADOWTLS" "$CLASH_SHADOWSOCKS" "$CLASH_TROJAN" "$CLASH_VMESS_WS" "$CLASH_VLESS_WS" "$CLASH_GRPC_REALITY" "$CLASH_ANYTLS")
CLASH2_PROXY_GROUPS_INSERT=("- ${NODE_NAME[11]} ${NODE_TAG[0]}" "- ${NODE_NAME[12]} ${NODE_TAG[1]}" "- ${NODE_NAME[13]} ${NODE_TAG[2]}" "- ${NODE_NAME[14]} ${NODE_TAG[3]}" "- ${NODE_NAME[15]} ${NODE_TAG[4]}" "- ${NODE_NAME[16]} ${NODE_TAG[5]}" "- ${NODE_NAME[17]} ${NODE_TAG[6]}" "- ${NODE_NAME[18]} ${NODE_TAG[7]}" "- ${NODE_NAME[20]} ${NODE_TAG[9]}" "- ${NODE_NAME[21]} ${NODE_TAG[10]}") CLASH2_PROXY_GROUPS_INSERT=("- ${NODE_NAME[11]} ${NODE_TAG[0]}" "- ${NODE_NAME[12]} ${NODE_TAG[1]}" "- ${NODE_NAME[13]} ${NODE_TAG[2]}" "- ${NODE_NAME[14]} ${NODE_TAG[3]}" "- ${NODE_NAME[15]} ${NODE_TAG[4]}" "- ${NODE_NAME[16]} ${NODE_TAG[5]}" "- ${NODE_NAME[17]} ${NODE_TAG[6]}" "- ${NODE_NAME[18]} ${NODE_TAG[7]}" "- ${NODE_NAME[20]} ${NODE_TAG[9]}" "- ${NODE_NAME[21]} ${NODE_TAG[10]}")
CLASH2_YAML=$(wget --no-check-certificate -qO- --tries=3 --timeout=2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash2) CLASH2_YAML=$(cat ${TEMP_DIR}/clash2)
for x in ${!CLASH2_PORT[@]}; do for x in ${!CLASH2_PORT[@]}; do
[[ ${CLASH2_PORT[x]} =~ [0-9]+ ]] && { CLASH2_YAML=$(sed "/proxy-groups:/i\ ${CLASH2_PROXY_INSERT[x]}" <<< "$CLASH2_YAML"); CLASH2_YAML=$(sed -E "/- name: (♻️ 自动选择|📲 电报消息|💬 OpenAi|📹 油管视频|🎥 奈飞视频|📺 巴哈姆特|📺 哔哩哔哩|🌍 国外媒体|🌏 国内媒体|📢 谷歌FCM|Ⓜ️ 微软Bing|Ⓜ️ 微软云盘|Ⓜ️ 微软服务|🍎 苹果服务|🎮 游戏平台|🎶 网易音乐|🎯 全球直连)|^rules:$/i\ ${CLASH2_PROXY_GROUPS_INSERT[x]}" <<< "$CLASH2_YAML"); } [[ ${CLASH2_PORT[x]} =~ [0-9]+ ]] && { CLASH2_YAML=$(sed "/proxy-groups:/i\ ${CLASH2_PROXY_INSERT[x]}" <<< "$CLASH2_YAML"); CLASH2_YAML=$(sed -E "/- name: (♻️ 自动选择|📲 电报消息|💬 OpenAi|📹 油管视频|🎥 奈飞视频|📺 巴哈姆特|📺 哔哩哔哩|🌍 国外媒体|🌏 国内媒体|📢 谷歌FCM|Ⓜ️ 微软Bing|Ⓜ️ 微软云盘|Ⓜ️ 微软服务|🍎 苹果服务|🎮 游戏平台|🎶 网易音乐|🎯 全球直连)|^rules:$/i\ ${CLASH2_PROXY_GROUPS_INSERT[x]}" <<< "$CLASH2_YAML"); }
done done
echo "$CLASH2_YAML" > ${WORK_DIR}/subscribe/clash2 echo "$CLASH2_YAML" > ${WORK_DIR}/subscribe/clash2
rm -f ${TEMP_DIR}/clash{,2}
} &>/dev/null } &>/dev/null
# 生成 ShadowRocket 订阅配置文件 # 生成 ShadowRocket 订阅配置文件
@@ -2933,7 +2996,7 @@ trojan://$TROJAN_PASSWORD@${SERVER_IP_1}:$PORT_TROJAN?security=tls&insecure=1&al
if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] || [[ "$IS_ARGO" = 'is_argo' && "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ]]; then if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] || [[ "$IS_ARGO" = 'is_argo' && "$NONINTERACTIVE_INSTALL" = 'noninteractive_install' ]]; then
local V2RAYN_SUBSCRIBE+=" local V2RAYN_SUBSCRIBE+="
---------------------------- ----------------------------
vmess://$(echo -n "{ \"v\": \"2\", \"ps\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"add\": \"${CDN[18]}\", \"port\": \"80\", \"id\": \"${UUID[18]}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"auto\", \"host\": \"$ARGO_DOMAIN\", \"path\": \"/$VMESS_WS_PATH\", \"tls\": \"\", \"sni\": \"\", \"alpn\": \"\" }" | base64 -w0)" vmess://$(echo -n "{ \"v\": \"2\", \"ps\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"add\": \"${CDN[17]}\", \"port\": \"80\", \"id\": \"${UUID[17]}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"auto\", \"host\": \"$ARGO_DOMAIN\", \"path\": \"/$VMESS_WS_PATH\", \"tls\": \"\", \"sni\": \"\", \"alpn\": \"\" }" | base64 -w0)"
[ "$ARGO_TYPE" = 'is_token_argo' ] && V2RAYN_SUBSCRIBE+=" [ "$ARGO_TYPE" = 'is_token_argo' ] && V2RAYN_SUBSCRIBE+="
# $(text 94) # $(text 94)
@@ -2941,7 +3004,7 @@ vmess://$(echo -n "{ \"v\": \"2\", \"ps\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\",
else else
WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local V2RAYN_SUBSCRIBE+=" WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local V2RAYN_SUBSCRIBE+="
---------------------------- ----------------------------
vmess://$(echo -n "{ \"v\": \"2\", \"ps\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"add\": \"${CDN[18]}\", \"port\": \"80\", \"id\": \"${UUID[18]}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"auto\", \"host\": \"$VMESS_HOST_DOMAIN\", \"path\": \"/$VMESS_WS_PATH\", \"tls\": \"\", \"sni\": \"\", \"alpn\": \"\" }" | base64 -w0) vmess://$(echo -n "{ \"v\": \"2\", \"ps\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"add\": \"${CDN[17]}\", \"port\": \"80\", \"id\": \"${UUID[17]}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"auto\", \"host\": \"$VMESS_HOST_DOMAIN\", \"path\": \"/$VMESS_WS_PATH\", \"tls\": \"\", \"sni\": \"\", \"alpn\": \"\" }" | base64 -w0)
# $(text 52)" # $(text 52)"
fi fi
@@ -3135,9 +3198,9 @@ anytls://${UUID[21]}@${SERVER_IP_1}:${PORT_ANYTLS}?security=tls&sni=${TLS_SERVER
local NODE_REPLACE+="\"${NODE_NAME[21]} ${NODE_TAG[10]}\"," local NODE_REPLACE+="\"${NODE_NAME[21]} ${NODE_TAG[10]}\","
{ {
# sing-box SFM SFA 模板 # 生成 sing-box SFM SFA SFI 订阅文件
local SING_BOX_JSON=$(wget --no-check-certificate -qO- --tries=3 --timeout=2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/sing-box) cat $TEMP_DIR/sing-box | sed "s#\"<OUTBOUND_REPLACE>\",#$OUTBOUND_REPLACE#; s#\"<NODE_REPLACE>\"#${NODE_REPLACE%,}#g" | ${WORK_DIR}/jq > ${WORK_DIR}/subscribe/sing-box
echo $SING_BOX_JSON | sed "s#\"<OUTBOUND_REPLACE>\",#$OUTBOUND_REPLACE#; s#\"<NODE_REPLACE>\"#${NODE_REPLACE%,}#g" | ${WORK_DIR}/jq > ${WORK_DIR}/subscribe/sing-box rm -f $TEMP_DIR/sing-box
} &>/dev/null } &>/dev/null
# 生成二维码 url 文件 # 生成二维码 url 文件
@@ -3268,7 +3331,7 @@ $(${WORK_DIR}/qrencode $SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto2)
cat ${WORK_DIR}/list cat ${WORK_DIR}/list
# 显示脚本使用情况数据 # 显示脚本使用情况数据
statistics_of_run-times get statistics_of_run_times get
} }
# 创建快捷方式 # 创建快捷方式
@@ -3317,16 +3380,16 @@ change_protocols() {
# 列出已安装协议 # 列出已安装协议
hint "\n $(text 63) (${#EXISTED_PROTOCOLS[@]})" hint "\n $(text 63) (${#EXISTED_PROTOCOLS[@]})"
for h in "${!EXISTED_PROTOCOLS[@]}"; do for h in "${!EXISTED_PROTOCOLS[@]}"; do
hint " $(asc $[h+97]). ${EXISTED_PROTOCOLS[h]} " hint " $(asc $(( h+97 ))). ${EXISTED_PROTOCOLS[h]} "
done done
# 从已安装的协议中选择需要删除的协议名,并存放在 REMOVE_PROTOCOLS,把保存的协议的协议存放在 KEEP_PROTOCOLS # 从已安装的协议中选择需要删除的协议名,并存放在 REMOVE_PROTOCOLS,把保存的协议的协议存放在 KEEP_PROTOCOLS
reading "\n $(text 64) " REMOVE_SELECT reading "\n $(text 64) " REMOVE_SELECT
# 统一为小写,去掉重复选项,处理不在可选列表里的选项,把特殊符号处理 # 统一为小写,去掉重复选项,处理不在可选列表里的选项,把特殊符号处理
REMOVE_SELECT=$(sed "s/[^a-$(asc $[${#EXISTED_PROTOCOLS[@]} + 96])]//g" <<< "${REMOVE_SELECT,,}" | awk 'BEGIN{RS=""; FS=""}{delete seen; output=""; for(i=1; i<=NF; i++){ if(!seen[$i]++){ output=output $i } } print output}') REMOVE_SELECT=$(sed "s/[^a-$(asc $(( ${#EXISTED_PROTOCOLS[@]} + 96 )))]//g" <<< "${REMOVE_SELECT,,}" | awk 'BEGIN{RS=""; FS=""}{delete seen; output=""; for(i=1; i<=NF; i++){ if(!seen[$i]++){ output=output $i } } print output}')
for ((j=0; j<${#REMOVE_SELECT}; j++)); do for ((j=0; j<${#REMOVE_SELECT}; j++)); do
REMOVE_PROTOCOLS+=("${EXISTED_PROTOCOLS[$[$(asc "$(awk "NR==$[j+1] {print}" <<< "$(grep -o . <<< "$REMOVE_SELECT")")") - 97]]}") REMOVE_PROTOCOLS+=("${EXISTED_PROTOCOLS[$(( $(asc "$(awk "NR==$[j+1] {print}" <<< "$(grep -o . <<< "$REMOVE_SELECT")")") - 97 ))]}")
done done
for k in "${EXISTED_PROTOCOLS[@]}"; do for k in "${EXISTED_PROTOCOLS[@]}"; do
@@ -3337,14 +3400,14 @@ change_protocols() {
if [ "${#NOT_EXISTED_PROTOCOLS[@]}" -gt 0 ]; then if [ "${#NOT_EXISTED_PROTOCOLS[@]}" -gt 0 ]; then
hint "\n $(text 65) (${#NOT_EXISTED_PROTOCOLS[@]}) " hint "\n $(text 65) (${#NOT_EXISTED_PROTOCOLS[@]}) "
for i in "${!NOT_EXISTED_PROTOCOLS[@]}"; do for i in "${!NOT_EXISTED_PROTOCOLS[@]}"; do
hint " $(asc $[i+97]). ${NOT_EXISTED_PROTOCOLS[i]} " hint " $(asc $(( i+97 ))). ${NOT_EXISTED_PROTOCOLS[i]} "
done done
reading "\n $(text 66) " ADD_SELECT reading "\n $(text 66) " ADD_SELECT
# 统一为小写,去掉重复选项,处理不在可选列表里的选项,把特殊符号处理 # 统一为小写,去掉重复选项,处理不在可选列表里的选项,把特殊符号处理
ADD_SELECT=$(sed "s/[^a-$(asc $[${#NOT_EXISTED_PROTOCOLS[@]} + 96])]//g" <<< "${ADD_SELECT,,}" | awk 'BEGIN{RS=""; FS=""}{delete seen; output=""; for(i=1; i<=NF; i++){ if(!seen[$i]++){ output=output $i } } print output}') ADD_SELECT=$(sed "s/[^a-$(asc $(( ${#NOT_EXISTED_PROTOCOLS[@]} + 96 )))]//g" <<< "${ADD_SELECT,,}" | awk 'BEGIN{RS=""; FS=""}{delete seen; output=""; for(i=1; i<=NF; i++){ if(!seen[$i]++){ output=output $i } } print output}')
for ((l=0; l<${#ADD_SELECT}; l++)); do for ((l=0; l<${#ADD_SELECT}; l++)); do
ADD_PROTOCOLS+=("${NOT_EXISTED_PROTOCOLS[$[$(asc "$(awk "NR==$[l+1] {print}" <<< "$(grep -o . <<< "$ADD_SELECT")")") - 97]]}") ADD_PROTOCOLS+=("${NOT_EXISTED_PROTOCOLS[$(( $(asc "$(awk "NR==$[l+1] {print}" <<< "$(grep -o . <<< "$ADD_SELECT")")") - 97 ))]}")
done done
fi fi
@@ -3841,7 +3904,7 @@ menu() {
} }
check_cdn check_cdn
statistics_of_run-times update sing-box.sh 2>/dev/null statistics_of_run_times update sing-box.sh 2>/dev/null
# 传参 # 传参
[[ "${*^^}" =~ '-E'|'-K' ]] && L=E [[ "${*^^}" =~ '-E'|'-K' ]] && L=E