应用程序重定向技术(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
  • ...
相关推荐
love530love12 小时前
Windows 多 Git 环境冲突:一个环境变量优先级引发的血案
人工智能·windows·git·环境变量·scoop
xuchaoxin137513 小时前
bash@bash帮助命令help@bash命令可用选项设置@bash -c@set命令@set --
bash
ol木子李lo1 天前
Linux 命令备忘录
linux·运维·服务器·windows·编辑器·ssh·bash
dingdingfish2 天前
Bash学习 - 第10章:Installing Bash
bash·make·shell·install·configure·5.3
dingdingfish3 天前
Bash学习 - 第8章:Command Line Editing,第3节:Readline Init File
bash·init·bind·readline
dingdingfish3 天前
Bash学习 - 第8章:Command Line Editing,第6-8节:Programmable Completion
bash·shell·completion·complete·compgen·compopt
dingdingfish4 天前
Bash学习 - 第8章:Command Line Editing,第4-5节:Bindable Readline Commands
bash·emacs·vi·bind·readline
香芋Yu4 天前
【从零构建AI Code终端系统】02 -- Bash 工具:一切能力的基础
开发语言·bash·agent·claude
dingdingfish5 天前
Bash学习 - 第7章:Job Control
bash·shell·wait·job