在网络受限的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, 能力不够.
版本V1
最终得到 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"; shiftlocal fake_net_call_countfake_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" >&2echo "[DEBUG] Current directory: $(pwd)" >&2printf '[DEBUG] Command: %s ' "$cmd" >&2printf '%q ' "$@" >&2printf '\n' >&2# 根据调用序号执行预设命令case "$fake_net_call_count" in*)# 未设置预设命令echo "[DEBUG] 未设置预设命令" >&2;;esacecho >&2# 永远返回成功return 0}# =====================================================# curl 壳# =====================================================curl() {__fake_net_common curl "$@"}# =====================================================# wget 壳# =====================================================wget() {__fake_net_common wget "$@"}# 导出函数,使其在子shell中也可用export -f curlexport -f wgetexport -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.shbash 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_ipwait
这3个 download xxxxx & 都是后台多线程执行的. 所以导致序号文件的读写出问题.
GPT的建议是在我们的 fake-curl-wget.sh 脚本中加入锁机制. 具体而言, 是用一个文件当作锁标志.
版本V2
我们把 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_FILEexport LOCK_FILE# =====================================================# 通用打印与执行逻辑# =====================================================__fake_net_common() {# 使用文件锁保护整个函数执行过程{flock 200 || {echo "[ERROR] 无法获取锁,超时" >&2return 1}local cmd="$1"; shiftlocal fake_net_call_countfake_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" >&2echo "[DEBUG] Current directory: $(pwd)" >&2printf '[DEBUG] Command: %s ' "$cmd" >&2printf '%q ' "$@" >&2printf '\n' >&2# 根据调用序号执行预设命令case "$fake_net_call_count" in*)# 未设置预设命令echo "[DEBUG] 未设置预设命令" >&2;;esacecho >&2} 200>"$LOCK_FILE"# 永远返回成功return 0}# =====================================================# curl 壳# =====================================================curl() {__fake_net_common curl "$@"}# =====================================================# wget 壳# =====================================================wget() {__fake_net_common wget "$@"}# 导出函数,使其在子shell中也可用export -f curlexport -f wgetexport -f __fake_net_common# ------------------------------------------# 提示加载成功# ------------------------------------------echo "[INFO] fake-curl-wget.sh 已加载"echo "[INFO] 所有 curl / wget 调用将被拦截"
再试试
source fake-curl-wget.shbash 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, 再结合我自己的整理, 得到:
版本V3
再试试
source fake-curl-wget.shbash 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的提示, 修改脚本.
版本V4
搞定!
上传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.zip10: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的回答








评论
发表评论