在网络受限的VPS上 运行一个脚本 向外访问网络时暂停 使用者进行替代操作
前言
上一篇我们解决DD脚本的问题的方案, 其实就可以用来解决所有网络受限的VPS环境运行脚本的问题 (当然整个操作看起来比较繁琐.
而且, 上一篇的方案只处理了curl的情况. 而常见的脚本, 有些是用curl访问网络, 有些是用wget.
能力弱一点的朋友, 不知道怎么改成处理wget的情况.
那么, 我们尝试做一个通用一点的方案.
而且考虑如何方便使用.
思路
我们
做一个 fake-curl-wget.sh 脚本.1) fake-curl-wget.sh 包含一个 curl() 的壳子, 和一个 wget() 的壳子2) 使用者在终端先 source fake-curl-wget.sh 再执行其它脚本3) 这样, 后面执行的脚本会调用到 fake-curl-wget.sh 中的 curl()壳子 和 wget()壳子4) 每次调用 curl 或 wget 时, 打印一个调用序号. 这个序号每次调用时, 自增1为了避免管道命令导致的序号问题, 使用临时文件保存序号.5) 对于所有 curl 和 wget 调用, 这个序号是统一. 先调用curl时, 序号为1.接着调用wget时, 序号为2.6) 输出 pwd 当前目录7) 输出 完整的 curl 命令和全部参数8) 输出 完整的 wget 命令和全部参数9) 这个curl壳 或 wget壳, 并不去真正访问网络10) 根据调用序号, 执行预设的命令. 如,cp file1 /path/to/file或cat file2用来替代 curl -LO 或 curl -Lo 的保存文件的命令或 curl -L 的输出到stdout的命令11) 这些预设命令是会被人工编辑而增加的. 用case实现 10) 的逻辑.12) 这个curl壳 或 wget壳, 永远返回成功.
实践与调试
把上面这一大段需求发给GPT.
得到的结果大方向是对的, 但是有小问题. 而且对话几次, 也不能让我满意.
还是要动用我的编码能力, 综合多个GPT的回答.
* 也许是我用的免费的GPT, 能力不够.
版本V0.1
最终得到 fake-curl-wget.sh 文件内容:
#!/usr/bin/env bash # ========================================== # fake-curl-wget.sh # 拦截 curl 和 wget 调用,用于调试/离线测试 # ==========================================
# 调用计数文件(全局共享) COUNT_FILE="${HOME}/fake_curl_wget_count.tmp" echo "0" > "$COUNT_FILE"
# 导出变量,使其在子shell中也可用 export COUNT_FILE
# ===================================================== # 通用打印与执行逻辑 # ===================================================== __fake_net_common() {
local cmd="$1"; shift local fake_net_call_count
fake_net_call_count=$(cat "$COUNT_FILE") fake_net_call_count=$((fake_net_call_count + 1)) echo "$fake_net_call_count" > "$COUNT_FILE"
echo "[DEBUG] curl/wget call # $fake_net_call_count" >&2 echo "[DEBUG] Current directory: $(pwd)" >&2
printf '[DEBUG] Command: %s ' "$cmd" >&2 printf '%q ' "$@" >&2 printf '\n' >&2
# 根据调用序号执行预设命令 case "$fake_net_call_count" in *) # 未设置预设命令 echo "[DEBUG] 未设置预设命令" >&2 ;; esac
echo >&2
# 永远返回成功 return 0 }
# ===================================================== # curl 壳 # ===================================================== curl() { __fake_net_common curl "$@" }
# ===================================================== # wget 壳 # ===================================================== wget() { __fake_net_common wget "$@" }
# 导出函数,使其在子shell中也可用 export -f curl export -f wget export -f __fake_net_common
# ------------------------------------------ # 提示加载成功 # ------------------------------------------ echo "[INFO] fake-curl-wget.sh 已加载" echo "[INFO] 所有 curl / wget 调用将被拦截"
我们以常见的233脚本为例.
假设我们的VPS网络有问题, 访问不了github.com, 还有一些其它网络问题. 用233脚本官方默认的方式调用失败了.
bash <(wget -qO- -o- https://github.com/233boy/Xray/raw/main/install.sh)
那么我们先把 https://github.com/233boy/Xray/raw/main/install.sh 用我们的办法先下载, 再上传到VPS上.
然后
source fake-curl-wget.sh bash install.sh
观察到了很奇怪的日志.
不仅序号都为1而且序号与命令和参数的打印也是顺序混乱的.
把我们的 fake-curl-wget.sh 脚本内容, 和 install.sh 脚本内容, 再加上日志, 全部复制粘贴问GPT. (感谢现在GPT的输入窗口足够大)
得知原因是在 install.sh 下面的代码中
[[ ! $is_core_file ]] && download core & [[ ! $local_install ]] && download sh & [[ $jq_not_found ]] && download jq & get_ip wait
这3个 download xxxxx & 都是后台多线程执行的. 所以导致序号文件的读写出问题.
GPT的建议是在我们的 fake-curl-wget.sh 脚本中加入锁机制. 具体而言, 是用一个文件当作锁标志.
版本V0.2
我们把 fake-curl-wget.sh 改成这样
#!/usr/bin/env bash # ========================================== # fake-curl-wget.sh # 拦截 curl 和 wget 调用,用于调试/离线测试 # ==========================================
# 调用计数文件(全局共享) COUNT_FILE="${HOME}/fake_curl_wget_count.tmp" echo "0" > "$COUNT_FILE"
# 锁文件 LOCK_FILE="${COUNT_FILE}.lock"
# 导出变量,使其在子shell中也可用 export COUNT_FILE export LOCK_FILE
# ===================================================== # 通用打印与执行逻辑 # ===================================================== __fake_net_common() {
# 使用文件锁保护整个函数执行过程 { flock 200 || { echo "[ERROR] 无法获取锁,超时" >&2 return 1 }
local cmd="$1"; shift local fake_net_call_count
fake_net_call_count=$(cat "$COUNT_FILE") fake_net_call_count=$((fake_net_call_count + 1)) echo "$fake_net_call_count" > "$COUNT_FILE"
echo "[DEBUG] curl/wget call # $fake_net_call_count" >&2 echo "[DEBUG] Current directory: $(pwd)" >&2
printf '[DEBUG] Command: %s ' "$cmd" >&2 printf '%q ' "$@" >&2 printf '\n' >&2
# 根据调用序号执行预设命令 case "$fake_net_call_count" in *) # 未设置预设命令 echo "[DEBUG] 未设置预设命令" >&2 ;; esac
echo >&2
} 200>"$LOCK_FILE"
# 永远返回成功 return 0 }
# ===================================================== # curl 壳 # ===================================================== curl() { __fake_net_common curl "$@" }
# ===================================================== # wget 壳 # ===================================================== wget() { __fake_net_common wget "$@" }
# 导出函数,使其在子shell中也可用 export -f curl export -f wget export -f __fake_net_common
# ------------------------------------------ # 提示加载成功 # ------------------------------------------ echo "[INFO] fake-curl-wget.sh 已加载" echo "[INFO] 所有 curl / wget 调用将被拦截"
再试试
source fake-curl-wget.sh bash install.sh
这下日志正常了.
但是多次执行, 发现日志中的 wget 命令的顺序会变化.
哎, 看来本文一开头, 我的口气太大了, 哈哈.
并不是所有的脚本在向外访问网络时, 用到的命令的次序都是固定的.
即使修改脚本, 把那几个download改成不后台了. wget 命令的顺序固定了.
[[ ! $is_core_file ]] && download core [[ ! $local_install ]] && download sh [[ $jq_not_found ]] && download jq
但是, 临时目录的目录名也有随机字符.
哎呀, 再次打脸了, 就算次序固定了, 也可能用到随机字符的临时目录呀.
不能提前编写预设命令.
我想了一个办法, 能不能让脚本暂停这在这里, 等使用者自己把文件上传到指定的位置, 再继续?
脚本暂停的方案
我想
1) 当根据序号 进行case逻辑 发现没有匹配的预设命令时, 脚本暂停. 等待使用者输入.2) 根据日志打印的 curl 或 wget 命令及参数. 使用者判断 当前序号的操作是要保存文件, 还是要输出信息到stdout.2a) 如果当前操作是保存文件, 则 使用者自己上传文件到指定位置. 输入 空. 脚本继续执行.2b) 如果当前操作是输出 信息到 stdout, 则 使用者输入 替代指令. 脚本执行替代指令.如, 使用者输入 echo "something" 或 cat /path/to/file
把这一段发给GPT, 再结合我自己的整理, 得到:
版本V0.3
再试试
source fake-curl-wget.sh bash install.sh
在保存文件的部分都是正常的.
在
wget --no-check-certificate -4 -qO- https://one.one.one.one/cdn-cgi/trace 时, 我输入
wget --no-check-certificate -4 -qO- https://www.cloudflare.com/cdn-cgi/trace 程序就卡死了.
拿着两个 .sh 的脚本内容复制粘贴到GPT里, 再加上刚刚的日志打印, 一起问GPT.
原因是 当执行我输入的 wget xxxx 时, 不是调用系统的wget, 而调用了我的 wget 壳子.
所以再根据GPT的提示, 修改脚本.
版本V0.4
搞定!
上传Github
后记
如果你看不懂 wget 命令和 curl 命令的参数, 你可以问GPT
以下是我的shell终端操作和日志
root@localhost:~# source fake-curl-wget.sh [INFO] fake-curl-wget.sh 已加载 [INFO] 所有 curl / wget 调用将被拦截 root@localhost:~# bash install.sh
........... Xray script by 233boy ..........
10:43:06) 开始安装... 10:43:06) 提醒!!! 无法设置自动同步时间, 可能会影响使用 VMess 协议. 10:43:06) 下载 Xray > https://github.com/xtls/xray-core/releases/latest/download/xray-linux-64.zip 10:43:06) 下载 Xray 脚本 > https://github.com/233boy/xray/releases/latest/download/code.zip [DEBUG] curl/wget call # 1 [DEBUG] Current directory: /root [DEBUG] Command: wget --no-check-certificate -4 -qO- https://one.one.one.one/cdn-cgi/trace [DEBUG] 未设置预设命令
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [WARN] 序号 1 未设置预设命令 请根据 curl/wget的原始命令及参数 进行操作: - 如需保存文件:请手动上传文件到目标位置,然后输入空行继续 - 如需输出到stdout:请输入替代命令(如: echo "something" 或 cat /path/file) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [INPUT] 请输入替代命令(或按回车表示文件已上传): wget --no-check-certificate -4 -qO- https://www.cloudflare.com/cdn-cgi/trace
[DEBUG] curl/wget call # 2 [DEBUG] Current directory: /root [DEBUG] Command: wget --no-check-certificate -t 3 -q -c https://github.com/xtls/xray-core/releases/latest/download/xray-linux-64.zip -O /tmp/tmp.ce4nDtgcDI/tmpcore [DEBUG] 未设置预设命令
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [WARN] 序号 2 未设置预设命令 请根据 curl/wget的原始命令及参数 进行操作: - 如需保存文件:请手动上传文件到目标位置,然后输入空行继续 - 如需输出到stdout:请输入替代命令(如: echo "something" 或 cat /path/file) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [INPUT] 请输入替代命令(或按回车表示文件已上传):
请问我现在应该做什么?
这是DeepSeek的回答
========







