在 Linux 运维或软件安装过程中,经常会遇到两种常见的脚本文件:很多初学者会疑惑:
.run 文件到底是什么?它和 .sh 有什么区别?是不是一种新的脚本语言?
实际上,.run 并不是一种新的脚本语言,本质上仍然是 Shell 脚本或可执行程序的封装形式。
一、什么是 .run 文件
.run 文件是 Linux 中常见的一种 可执行安装包格式,通常用于:
软件安装程序
驱动程序安装
二进制程序分发
自解压安装包
常见的软件安装包:
NVIDIA 驱动
VMware Tools
某些商业软件
例如:
NVIDIA-Linux-x86_64-550.54.runVMware-Workstation-Full-17.0.0.run
运行方式通常是:
chmod +x file.run./file.run
本质原理
.run 文件通常是以下结构之一:
1️⃣ Shell脚本 + 压缩数据
#!/bin/bash安装逻辑自解压逻辑程序数据
2️⃣ 自解压安装包
脚本头tar.gz 压缩包
执行时:
先执行脚本
解压内部文件
执行安装程序
二、什么是 .sh 文件
.sh 文件是最常见的 Shell 脚本文件,用于编写 Linux 自动化脚本。
常见用途:
例如:
#!/bin/bashecho "Hello Linux"datewhoami
执行方式:
bash script.sh
或者
chmod +x script.sh./script.sh
.sh 的本质就是 纯文本 Shell 脚本。
三、.run 与 .sh 的核心区别
| 对比项 | .run | .sh |
|---|
| 文件类型 | 安装程序/可执行包 | Shell脚本 |
| 本质 | Shell脚本或二进制封装 | 纯Shell脚本 |
| 是否可包含程序 | 可以 | 不可以 |
| 是否自解压 | 常见 | 不支持 |
| 使用场景 | 软件安装包 | 自动化脚本 |
| 是否统一标准 | 没有统一标准 | 标准Shell脚本 |
简单理解:
.sh 是脚本.run 是 安装程序封装
四、.run 文件内部结构解析
我们可以用 head 查看 .run 文件头部:
head -n 20 example.run
示例:
#!/bin/sh# Self-extracting archiveecho "Extracting files..."ARCHIVE=`awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' $0`tail -n+$ARCHIVE $0 | tar xzexit 0__ARCHIVE_BELOW__解释:
| 部分 | 作用 |
|---|
| shebang | 指定解释器 |
| shell脚本 | 控制安装逻辑 |
| archive | 压缩程序数据 |
执行 .run 时:
1️⃣ 执行脚本2️⃣ 解压 archive3️⃣ 执行安装
五、.run 文件简单示例
下面演示如何自己制作一个 .run 安装程序。
5.1、 创建程序目录
mkdir myappecho "Hello MyApp" > myapp/app.txt
5.2、 打包程序
tar czf myapp.tar.gz myapp
5.3、 创建 run 安装脚本
#!/bin/bashecho "Installing MyApp..."ARCHIVE_LINE=$(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' $0)tail -n+$ARCHIVE_LINE $0 | tar xzecho "Install complete"exit 0__ARCHIVE_BELOW__
5.4、 合并脚本和数据
cat install.sh myapp.tar.gz > myapp.run
5.5、 添加执行权限
chmod +x myapp.run
运行:
./myapp.run
输出:
Installing MyApp...Install complete
程序会自动解压。

六、.run 常见应用场景
6.1、软件安装包
方式 1:目录式 run
例如:
VMware-Workstation-17.run
运行:
sudo ./VMware-Workstation-17.run
假设你有两个离线软件包,需要通过一个 install.run 一起安装:
app1_1.0.0_amd64.deb
app2-2.3.1.tar.gz
目标是做到:
一次执行 ./install.run
自动安装 .deb
自动解压并部署 tar.gz
自动创建软链接
自动输出安装结果
示例目录结构
先准备一个目录,例如:
offline_installer/├── install.run├── packages/│ ├── app1_1.0.0_amd64.deb│ └── app2-2.3.1.tar.gz└── scripts/ └── post_install.sh
说明:
install.run 样例:
#!/bin/bashset -e######################################### Offline Installer Demo# 安装两个离线软件包:# 1) app1_1.0.0_amd64.deb# 2) app2-2.3.1.tar.gz########################################APP1_DEB="app1_1.0.0_amd64.deb"APP2_TAR="app2-2.3.1.tar.gz"INSTALL_BASE="/opt"APP2_DIR="${INSTALL_BASE}/app2"APP2_LINK="/usr/local/bin/app2"SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"PKG_DIR="${SCRIPT_DIR}/packages"SCRIPT_POST="${SCRIPT_DIR}/scripts/post_install.sh"LOG_FILE="/tmp/offline_install_$(date +%Y%m%d_%H%M%S).log"log() { echo "[INFO] $1" | tee -a "$LOG_FILE"}warn() { echo "[WARN] $1" | tee -a "$LOG_FILE"}error() { echo "[ERROR] $1" | tee -a "$LOG_FILE" exit 1}check_root() { if [ "$EUID" -ne 0 ]; then error "请使用 root 或 sudo 执行该安装程序。" fi}check_files() { [ -f "${PKG_DIR}/${APP1_DEB}" ] || error "未找到 ${PKG_DIR}/${APP1_DEB}" [ -f "${PKG_DIR}/${APP2_TAR}" ] || error "未找到 ${PKG_DIR}/${APP2_TAR}"}install_deb() { log "开始安装 DEB 包:${APP1_DEB}" if command -v dpkg >/dev/null 2>&1; then dpkg -i "${PKG_DIR}/${APP1_DEB}" 2>&1 | tee -a "$LOG_FILE" || true else error "系统未找到 dpkg,无法安装 deb 包。" fi # 如果系统有 apt-get,可以尝试修复依赖 if command -v apt-get >/dev/null 2>&1; then log "尝试修复依赖(若依赖已离线准备好或系统已有则可成功)" apt-get install -f -y 2>&1 | tee -a "$LOG_FILE" || warn "依赖修复未成功,请确认依赖是否已提前准备。" else warn "未找到 apt-get,跳过依赖修复。" fi log "DEB 包安装步骤完成。"}install_tar() { log "开始安装 TAR.GZ 包:${APP2_TAR}" mkdir -p "$APP2_DIR" # 先清理旧版本(可按需删除) rm -rf "${APP2_DIR:?}/"* tar -xzf "${PKG_DIR}/${APP2_TAR}" -C "$APP2_DIR" --strip-components=1 2>&1 | tee -a "$LOG_FILE" # 假设 tar.gz 解压后主程序叫 app2 if [ -f "${APP2_DIR}/app2" ]; then chmod +x "${APP2_DIR}/app2" ln -sf "${APP2_DIR}/app2" "$APP2_LINK" log "已创建软链接:${APP2_LINK} -> ${APP2_DIR}/app2" else warn "未找到 ${APP2_DIR}/app2,请根据实际程序名修改脚本。" fi log "TAR.GZ 包安装完成。"}run_post_install() { if [ -f "$SCRIPT_POST" ]; then log "执行安装后脚本:${SCRIPT_POST}" chmod +x "$SCRIPT_POST" "$SCRIPT_POST" 2>&1 | tee -a "$LOG_FILE" else warn "未找到 post_install.sh,跳过安装后处理。" fi}show_summary() { echo echo "======================================" echo "安装完成" echo "日志文件:$LOG_FILE" echo "DEB包:${APP1_DEB}" echo "TAR包:${APP2_TAR}" echo "APP2安装目录:${APP2_DIR}" echo "APP2启动命令:${APP2_LINK}" echo "======================================" echo}main() { log "离线安装开始" check_root check_files install_deb install_tar run_post_install show_summary}main "$@"post_install.sh 样例
如果你想在安装完成后做一些初始化动作,比如创建目录、配置文件、日志目录,可以配一个脚本:
#!/bin/bashmkdir -p /etc/app2mkdir -p /var/log/app2if [ ! -f /etc/app2/app2.conf ]; then cat > /etc/app2/app2.conf <<EOF# app2 default configport=8080log_level=infoEOFfiecho "post install finished."
赋予执行权限
给安装脚本加执行权限:
chmod +x install.runchmod +x scripts/post_install.sh
然后执行:
sudo ./install.run
如果.deb也有离线依赖,怎么一起装
这是实际环境里最常见的问题。因为 .deb 很可能依赖其他 .deb,所以更稳妥的做法是:
把所有依赖包都放到 packages/ 下,然后统一安装。
例如目录改成:
offline_installer/├── install.run├── packages/│ ├── liba.deb│ ├── libb.deb│ ├── app1_1.0.0_amd64.deb│ └── app2-2.3.1.tar.gz
安装逻辑可以改成:
install_all_debs() { log "开始安装目录中的全部 DEB 包" find "${PKG_DIR}" -maxdepth 1 -name "*.deb" | sort | while read -r deb_file; do log "安装: ${deb_file}" dpkg -i "$deb_file" 2>&1 | tee -a "$LOG_FILE" || true done if command -v apt-get >/dev/null 2>&1; then apt-get install -f -y 2>&1 | tee -a "$LOG_FILE" || warn "依赖修复未成功" fi log "全部 DEB 包安装完成"}然后把主流程里的 install_deb 换成 install_all_debs。
如果想做成“单文件 run 包” 通常有两种方式:
就是现在这种:
一个 install.run
外加 packages/ 目录
优点:
缺点:
方式 2:单文件自解压 run
把脚本和安装包打到一个文件里,运行时先解压再安装。这种更像真正的软件发行包。
单文件.run自解压样例
先写一个 installer_stub.sh:
#!/bin/bashset -eTMP_DIR="/tmp/offline_bundle_$$"ARCHIVE_LINE=$(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0")mkdir -p "$TMP_DIR"tail -n +"$ARCHIVE_LINE" "$0" | tar -xz -C "$TMP_DIR"chmod +x "$TMP_DIR/install.run"exec "$TMP_DIR/install.run"exit 0__ARCHIVE_BELOW__然后把你的安装目录打包:
tar -czf payload.tar.gz packages scripts install.runcat installer_stub.sh payload.tar.gz > offline_bundle.runchmod +x offline_bundle.run
运行时:
sudo ./offline_bundle.run
它会自动:
解压内嵌的压缩包到 /tmp
执行里面真正的 install.run
完成两个软件包的安装
6.2、 驱动程序安装
例如:
NVIDIA-Linux-x86_64.run
6.3、 商业软件发布
很多商业软件使用 .run:
JetBrains Toolbox
游戏服务器
数据库工具
原因:
七、.run 与 Linux 软件包的区别
| 类型 | 示例 | 特点 |
|---|
| run | xxx.run | 通用安装包 |
| rpm | xxx.rpm | RedHat 系 |
| deb | xxx.deb | Debian 系 |
| tar.gz | xxx.tar.gz | 源码包 |
.run 的优势:
不依赖系统发行版
自带安装逻辑
可跨 Linux 发行版
八、如何查看 .run 文件内容
方法一:
sh file.run --extract
方法二:
tail
tail -n +100 file.run
方法三:
strings file.run

九、安全注意事项
运行 .run 文件前建议:
1 查看文件内容
less file.run
2 检查来源
确保来自官方。
3 不要随便 root 运行
除非必须。
十、总结
.run 文件并不是一种新的脚本语言,本质上是一种 自解压可执行安装包格式。
核心区别总结:
| 类型 | 本质 |
|---|
.sh | Shell脚本 |
.run | 可执行安装程序 |
理解一句话:
.sh 是脚本.run 是 安装包
在 Linux 软件分发领域,.run 由于 跨发行版、使用简单、无需依赖包管理器,仍然被大量软件厂商使用。