应用程序重定向技术(Shim)

应用程序重定向(Shim)

Window和Linux系统提供的ln/mklink 虽然很好用,但是不够灵活,所以,在很多程序替代时,需要一个同名字的程序作为中转。

参考scoop的实现:

Scoop 不会把每个软件的可执行文件路径直接添加到系统的 PATH 环境变量中,而是采用一种叫 shim(垫片/代理) 的机制:

  • 在 Scoop 的 shims 目录 (通常是 ~\scoop\shims)中为每个可执行文件创建一个轻量级的代理(.exe.bat 文件)。
  • 将这个 shims 目录一次性加入系统 PATH
  • 当你在命令行输入 gitnodepython 等命令时,实际运行的是 shims 目录下的代理程序,它会自动转发到真实程序的位置。

windows下可以使用scoop的shim方案:

https://github.com/ScoopInstaller/Scoop/tree/master/supporting/shims

Linux下没有现成的实现

但是可以使用bash脚本install-shim.sh替代:

bash 复制代码
#!/bin/bash

# ==========================================
# Shim 安装器
# 功能:将模板脚本中的占位符替换为实际值,并安装到 /usr/bin
# 用法:sudo ./install-shim.sh <目标文件名> <真实程序路径> <基础参数...>
# ==========================================

# 检查是否为 root (因为要写入 /usr/bin)
if [ "$EUID" -ne 0 ]; then
    echo "错误: 此脚本必须以 root 权限运行 (sudo)" >&2
    echo "用法: sudo $0 <命令名> <真实路径> [基础参数...]"
    exit 1
fi

# 检查参数数量
if [ $# -lt 2 ]; then
    echo "错误: 参数不足" >&2
    echo "用法: sudo $0 <命令名> <真实路径> [基础参数...]"
    echo "示例: sudo $0 firefox /opt/firefox/firefox '--no-sandbox'"
    exit 1
fi

# --- 解析参数 ---
# $1 是安装后的命令名
CMD_NAME="$1"
# $2 是真实路径
REAL_PATH="$2"
# shift 2 表示移除前两个参数,剩下的都是基础参数
shift 2
BASE_ARGS="$*" # 将剩余所有参数合并为一个字符串

# 安装目标路径
INSTALL_PATH="/usr/bin/$CMD_NAME"

# --- 检查目标程序是否存在 ---
if [ ! -x "$REAL_PATH" ]; then
    echo "错误: 真实程序 '$REAL_PATH' 不存在或不可执行" >&2
    exit 1
fi

# --- 检查是否已存在同名命令 ---
if command -v "$CMD_NAME" &> /dev/null; then
    echo "警告: 命令 '$CMD_NAME' 已存在。"
    read -p "是否覆盖现有命令? (y/N): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        echo "操作已取消。"
        exit 1
    fi
fi

# --- 定义原始 Shim 模板 ---
# 这里直接使用你提供的原始脚本内容,仅替换 # 为实际值
cat > "/tmp/$CMD_NAME.sh" << EOF
#!/bin/bash

# ==========================================
# Linux Shim 模拟脚本
# 功能:定义固定路径和基础参数,附加用户输入
# ==========================================

# 目标程序的路径 (建议绝对路径)
TARGET_PATH="$REAL_PATH"

# 基础参数 (Shim 固定传递的参数)
BASE_ARGS="$BASE_ARGS"

# --- 2. 核心逻辑 ---

# 检查目标文件是否存在
if [ ! -x "\$TARGET_PATH" ]; then
    echo "错误: 无法执行目标程序 '\$TARGET_PATH'" >&2
    echo "请确保文件存在且具有可执行权限 (chmod +x)" >&2
    exit 1
fi

# --- 3. 执行目标程序 (核心) ---
# "\$@" 代表所有传递给脚本的参数
# exec 替换当前进程镜像,使得目标程序直接接管当前进程 (PID 不变)

# 构建完整的命令行
FULL_COMMAND=("\$TARGET_PATH" \$BASE_ARGS "\$@")

# dump cmd
echo "CMD:" $FULL_COMMAND

# 执行 (exec 会用新程序替换当前 Shell 进程)
exec "\${FULL_COMMAND[@]}"

# 如果 exec 失败,脚本会继续执行到这里
echo "错误: 启动失败" >&2
exit 1
EOF

# --- 安装到 /usr/bin ---
echo "正在安装 '$CMD_NAME' 到 $INSTALL_PATH ..."

# 移动文件并重命名
mv "/tmp/$CMD_NAME.sh" "$INSTALL_PATH"

# 设置可执行权限 (chmod +x)
chmod +x "$INSTALL_PATH"

# --- 完成 ---
echo "安装成功!"
echo "现在你可以直接运行命令: $CMD_NAME"

使用时候:

bash 复制代码
chmod +x install-shim.sh
sudo ./install-shim.sh mycmd /home/user/app/real_app --debug --config=/tmp/cfg.ini

sudo ./install-shim.sh node `which bun`
sudo ./install-shim.sh npx `which bunx`

使用场景

  • bun 替代 node
  • bunx 替代 npx
  • ...
相关推荐
波特率1152008 小时前
bash命令进阶学习(Shell 元字符)
linux·bash·shell
knighthood20011 天前
ROS1中source xxx.bash失效
开发语言·bash
IMPYLH1 天前
Bash 的 basenc 命令
linux·运维·服务器·bash·shell
IMPYLH1 天前
Linux 的 arch 命令
linux·运维·服务器·bash
Be for thing1 天前
Bash 编程语法
学习·bash
IMPYLH2 天前
Linux 的 base64 命令
linux·运维·服务器·bash·shell
IMPYLH2 天前
Linux 的 base32 命令
linux·运维·服务器·bash·shell
LuL_Vegetable2 天前
写一个Linux服务器自动tcpdum抓包脚本
linux·wireshark·bash·tcpdump
勿芮介4 天前
【研发工具】OpenClaw基础环境安装全教程-Node\NVM\PNPM\Bash
开发语言·node.js·bash·ai编程
御坂10101号6 天前
「2>&1」是什么意思?半个世纪的 Unix 谜题
java·数据库·bash·unix