多shell脚本嵌套调用的环境 向外访问网络时暂停 使用者进行替代操作

前言

上一篇我们将 向外访问网络时暂停 使用者进行替代操作 的方案应用在了 安装233boy 脚本上面

进一步的, 能不能继续拓展应用范围, 用在, 比如, 我自己的 极简一键脚本中?
bash <(curl -L https://github.com/crazypeace/xray-vless-reality/raw/main/install.sh)

试试

发现有问题.

我的脚本调用了xray官方安装脚本, 在这个嵌套调用的场景下, 被嵌套调用的脚本里的网络访问就没有被抓到.

去问了好多个GPT, 回答了一堆什么线程啊, 进程啊, 环境啊, 继承啊, ... 
给了我几个解决方案, 试了一下也是不行. 说明回答的那些理论就是狗屁.

改进

那就来个根本的方案, 在系统PATH中安插假的 curl 和 wget.

我们上个方案里的 curl, wget, __fake_net_common 函数, 都变成可执行文件, 放到 PATH里去. 逻辑都是现成的, 不用大改.
最终我们得到这样的 4 个脚本
fake-curl-wget-v2.sh
#!/usr/bin/env bash
# ==========================================
# 拦截 curl 和 wget 调用,用于调试/离线测试
# ==========================================

# 在PATH中设置假命令 curl wget
mkdir -p /tmp/fakebin
if [[ ":$PATH:" != *:/tmp/fakebin:* ]]; then
  export PATH="/tmp/fakebin:$PATH"
fi

# 清理调用记数文件
rm /tmp/fakebin/*

# 放入假命令文件
cp __fake_net_common.sh /tmp/fakebin/fake_net_common
chmod +x $_
cp __fake_curl.sh /tmp/fakebin/curl
chmod +x $_
cp __fake_wget.sh /tmp/fakebin/wget
chmod +x $_

# ------------------------------------------
# 提示加载成功
# ------------------------------------------
echo "[INFO] 所有 curl / wget 调用将被拦截"

__fake_net_common.sh
#!/usr/bin/env bash

# 调用计数文件(全局共享)
COUNT_FILE="/tmp/fakebin/fake_curl_wget_count.tmp"
# 如果文件不存在, 初始化为0
if [[ ! -f "$COUNT_FILE" ]]; then
    echo "0" > "$COUNT_FILE"
fi

# 锁文件
LOCK_FILE="${COUNT_FILE}.lock"

# 使用文件锁保护整个执行过程
{
    flock 200 || {
        echo "[ERROR] 无法获取锁,超时" >&2
        return 1
    }

    cmd="$1"; shift

    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

    # 是否找到预设命令
    has_preset=0
    
    # 根据调用序号执行预设命令
    case "$fake_net_call_count" in
#           1)
#               # 示例:第1次调用的预设命令
#               # echo "preset response for call 1"
#               has_preset=1
#               ;;
        *)
            # 未设置预设命令
            echo "[DEBUG] 未设置预设命令" >&2
            has_preset=0
            ;;
    esac

    echo >&2

    # 如果没有预设命令,进入交互模式
    if [[ "$has_preset" -eq 0 ]]; then
        echo "[WARN] 序号 $fake_net_call_count 未设置预设命令" >&2
        echo "" >&2
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
        echo "请根据 curl/wget的原始命令及参数 进行操作:" >&2
        echo " - 如需保存文件:请手动上传文件到目标位置,然后输入空行继续" >&2
        echo ' - 如需输出到stdout:请输入替代命令(如: echo "something" 或 cat /path/file)' >&2
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
        echo "[INPUT] 请输入替代命令(或按回车表示文件已上传): " >&2

        # 读取用户输入
        read -r user_input </dev/tty

        # 用户输入空行,表示文件已手动上传
        # 什么都不用做

        # 用户输入非空行, 则视为替代命令,执行它
        if [[ -n "$user_input" ]]; then
            # 临时移除fake路径,使用真实的curl/wget
            export PATH=$(echo "$PATH" | sed 's|^\(/tmp/fakebin:\)\+||')
            
            eval "$user_input"
            echo >&2
            
            # 恢复PATH 加入fake路径
            export PATH="/tmp/fakebin:$PATH"
        fi
    fi

} 200>"$LOCK_FILE"

# 永远返回成功
exit 0

__fake_curl.sh
fake_net_common curl "$@"

__fake_wget.sh
fake_net_common wget "$@"

我们把它们4个都上传到VPS上, 再试试.

搞定!


Github



评论

The Hot3 in Last 7 Days

酒馆SillyTavern 玩英文角色卡 也能以中文输出 设置世界书Lorebooks

搭 Docker版 Sub-Store 带 http-meta 实现 集合订阅 测延迟 排序 筛选 生成新订阅 定时任务上传Gist