如何创建相对于其他符号链接的符号链接?
首先你得明确一个关键:符号链接的相对路径是相对于该链接所在的实际物理目录,而不是你访问它时经过的符号链接路径。这就是为什么现在27015/server/cstrike/hltv会指向不存在的根目录hltv——这个链接实际在/server/cstrike目录下,../../hltv的解析起点是/server/cstrike,最终自然指向了根目录的hltv。
要满足你的需求,没法直接通过共享/server/cstrike/hltv实现(因为单个静态软链接不可能同时指向两个不同目标),但我们可以用ln调整目录结构,或者结合Linux的挂载特性来解决,以下是两种可行方案:
方案一:用ln构建实例专属的cstrike目录
这个方案保留/server的共享内容,但给每个实例创建专属的cstrike目录,其中仅hltv指向实例自身的目录,其他文件/目录都链接到共享的/server/cstrike:
针对27015实例的操作:
- 创建实例专属的
cstrike目录:
mkdir -p /27015/cstrike
- 进入该目录,把
/server/cstrike下除hltv外的所有内容链接过来:
cd /27015/cstrike for item in /server/cstrike/*; do item_name=$(basename "$item") if [ "$item_name" != "hltv" ]; then ln -s "$item" "./$item_name" fi done
- 创建指向实例自身
hltv的链接:
ln -s ../hltv ./hltv
- 重构
27015/server,让它的cstrike指向实例专属目录(先删除原链接,再重新构建):
rm -f /27015/server mkdir -p /27015/server cd /27015/server # 链接/server下除cstrike外的所有内容 for item in /server/*; do item_name=$(basename "$item") if [ "$item_name" != "cstrike" ]; then ln -s "$item" "./$item_name" fi done # 链接实例专属的cstrike ln -s ../cstrike ./cstrike
针对27016实例,重复上述步骤,把所有路径中的27015替换为27016即可。
这个方案的优势是不需要特殊权限,完全用ln就能实现;缺点是当/server或/server/cstrike下的文件更新时,需要手动同步实例目录下的链接。
方案二:用绑定挂载+命名空间(进阶)
如果你想保留原有的2701X/server指向/server的结构,可以利用Linux的挂载命名空间和绑定挂载,给每个实例单独挂载自身的hltv到/server/cstrike/hltv,但这个方案需要root权限,适合以服务方式运行的实例:
- 先删除原有的
/server/cstrike/hltv链接:
rm -f /server/cstrike/hltv
- 对于每个实例,在启动时进入独立的挂载命名空间,再绑定挂载自身的
hltv到目标位置:
# 以27015为例,假设你的服务器启动命令是`./run_server` unshare -m sh -c "mount --bind /27015/hltv /server/cstrike/hltv && cd /27015 && ./run_server"
这样,在这个实例的专属命名空间里,/server/cstrike/hltv会指向/27015/hltv,其他实例的挂载不受影响。
这个方案的优势是不需要修改原有目录结构,共享的/server内容可以直接更新;缺点是需要root权限,且实例必须通过unshare启动。
总结:如果没有root权限,优先选方案一;如果想保留原有目录结构且有root权限,可以尝试方案二。
备注:内容来源于stack exchange,提问作者Evgeniy

