当前位置: 首页 > news >正文

Linux exec 命令详解

一、核心概念

exec 在 Linux 中有两个层面的含义:

层面 说明
Shell 内置命令 Bash/Zsh 等 shell 提供的 exec 命令,用于用新程序替换当前 shell 进程
系统调用家族 execve() 等 C 库函数,是进程映像替换的底层机制

核心机制:进程替换(Process Replacement)exec 不会创建新进程,而是将当前进程的地址空间完全替换为新程序的地址空间,PID 保持不变

Shell 进程 (PID=1234) ──exec──> 新程序 (PID=1234)

二、Shell 内置 exec 命令

2.1 基本语法

exec [选项] [-a name] [command [arguments]]
exec [选项] [redirection]

2.2 两种模式

模式一:执行程序替换(Program Replacement)

exec /path/to/program [args...]

效果:当前 shell 进程被完全替换为指定程序。执行后,shell 不再存在,程序结束后直接返回到 shell 的父进程。

# 示例:当前 shell 被替换为 vim
exec vim /etc/hosts
# vim 退出后,不会回到原 shell,而是直接退出终端

模式二:仅重定向(Redirection Only)

exec > output.log 2>&1

效果:不执行程序,仅改变当前 shell 的文件描述符重定向。后续所有命令的输出都会重定向到指定文件。


三、详细用法与示例

3.1 程序替换场景

场景 1:在脚本中切换解释器

#!/bin/bash
echo "This is bash"
exec python3 << 'EOF'
print("Now running Python in the same process")
EOF
# 这行不会执行,因为 bash 已被替换
echo "Back to bash"

⚠️ 注意:exec python3 后,原 bash 脚本中后续命令不会执行

场景 2:安全地降级权限(配合 suid)

#!/bin/bash
# 脚本以 root 运行,但需要用普通用户执行主程序
exec su -c "/path/to/app" normaluser

场景 3:守护进程启动(经典用法)

#!/bin/bash
# 关闭标准输入
exec 0</dev/null
# 重定向标准输出和错误到日志
exec 1>>/var/log/myapp.log
exec 2>&1
# 替换为实际程序
exec /usr/bin/myapp

3.2 文件描述符重定向场景

打开文件用于读写

# 打开文件描述符 3 用于写入
exec 3> /tmp/fd3.log
echo "Written to fd 3" >&3
exec 3>&-   # 关闭 fd 3

读取文件

# 打开文件描述符 4 用于读取
exec 4< /etc/passwd
read line <&4
echo "$line"
exec 4<&-   # 关闭 fd 4

同时读写

exec 5<> /tmp/dual.log
echo "Hello" >&5
exec 5<&-   # 关闭读取端
exec 5>&-   # 关闭写入端

经典:脚本日志重定向

#!/bin/bash
LOGFILE="/var/log/myscript.log"
exec > >(tee -a "$LOGFILE") 2>&1
echo "All output goes to both terminal and log file"

3.3 配合 source. 的区别

命令 是否创建新进程 是否替换当前进程 用途
exec program 替换当前 shell 为 program
source script 在当前 shell 中执行脚本
./script 创建子进程执行脚本

四、系统调用层面的 exec 家族

4.1 函数家族概览

#include <unistd.h>int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);

4.2 命名规则

后缀 含义
l list — 参数以可变参数列表形式传递(如 execl
v vector — 参数以数组形式传递(如 execv
e environment — 允许自定义环境变量
p pATH — 在 PATH 环境变量中搜索可执行文件

4.3 调用示例

#include <unistd.h>
#include <stdio.h>int main() {// execl: 参数逐个列出,以 NULL 结尾execl("/bin/ls", "ls", "-l", "/tmp", NULL);// 如果 exec 成功,下面这行不会执行perror("execl failed");return 1;
}
// execvp: 使用数组和 PATH 搜索
char *args[] = {"ls", "-l", "/tmp", NULL};
execvp("ls", args);  // 会在 PATH 中查找 ls

4.4 exec 与 fork 的配合

exec 通常与 fork() 配合使用,这是创建新进程的标准模式:

pid_t pid = fork();
if (pid == 0) {// 子进程:替换为新程序execl("/bin/echo", "echo", "Hello from child", NULL);perror("execl failed");_exit(1);  // exec 失败时必须退出
} else if (pid > 0) {// 父进程:等待子进程waitpid(pid, NULL, 0);
}

执行流程

父进程 (PID=1000) ──fork()──> 子进程 (PID=1001)│└──exec()──> /bin/echo (PID=1001)

五、高级用法

5.1 使用 exec 改变脚本自身的文件描述符

#!/bin/bash# 保存原始 stdout
exec 3>&1# 将所有输出重定向到日志
exec > /tmp/script.logecho "This goes to log"# 恢复原始 stdout
exec 1>&3
echo "This goes to terminal"exec 3>&-  # 关闭备份描述符

5.2 在函数中使用 exec

my_function() {local fdexec {fd}> /tmp/func.log   # 自动分配文件描述符echo "Log entry" >&$fdexec {fd}>&-               # 关闭
}

5.3 配合 trap 做清理

#!/bin/bash
cleanup() {exec 3>&- 2>/dev/null
}
trap cleanup EXITexec 3> /tmp/important.log
echo "Critical data" >&3

六、常见陷阱与注意事项

6.1 exec 后代码不再执行

#!/bin/bash
exec /bin/true
echo "NEVER REACHED"  # 这行永远不会执行

6.2 exec 失败不会自动退出

#!/bin/bash
exec /nonexistent/program
echo "Still running!"  # 如果 exec 失败,这行会执行!

正确做法

exec /nonexistent/program || { echo "exec failed"; exit 1; }

6.3 文件描述符泄漏

使用 exec 打开的文件描述符不会自动关闭,必须显式关闭:

exec 3> /tmp/file
# ... 使用 fd 3 ...
exec 3>&-   # 必须关闭,否则泄漏

6.4 与 nohupdisown 的区别

特性 exec program nohup program disown
进程替换
SIGHUP 免疫
输出重定向 手动 自动到 nohup.out

七、实际应用场景

场景 1:容器入口脚本

#!/bin/bash
# entrypoint.sh
set -e# 配置环境
export DB_HOST=${DB_HOST:-localhost}# 重定向日志
exec > >(tee /var/log/app/stdout.log)
exec 2> >(tee /var/log/app/stderr.log >&2)# 替换为实际应用(PID 1 保持为应用进程)
exec /usr/bin/myapp "$@"

在容器中,exec 确保应用进程接管 PID 1,从而正确接收 SIGTERM 信号。

场景 2:Shell 切换

# 从 bash 切换到 zsh,保持当前目录和环境
exec zsh

场景 3:权限隔离脚本

#!/bin/bash
# 先以 root 执行初始化,然后降级运行主程序
chown -R appuser:appuser /data
exec su -s /bin/sh -c '/usr/bin/myapp' appuser

八、总结速查表

用法 命令示例 效果
替换为程序 exec vim file Shell → vim,PID 不变
输出重定向 exec > log.txt 后续命令输出到文件
输入重定向 exec < input.txt 后续命令从文件读取
打开 FD exec 3> file 创建文件描述符 3
关闭 FD exec 3>&- 关闭文件描述符 3
复制 FD exec 3>&1 将 fd 3 指向 stdout
自动分配 FD exec {fd}> file Bash 自动分配 fd 编号

http://www.jsqmd.com/news/1361423/

相关文章:

  • TripoSR技术深度解析:单图像快速3D重建的实现原理与架构设计
  • 专家移植技术揭秘:fuse-1 Lite如何融合LFM2.5与Qwen3.6实现高效编码
  • 终极指南:通过Pymaker Python API轻松交互Maker Protocol智能合约
  • 2026年盒马提货券回收到底值不值?手里有券的人一定要看看 - 沃卡回收
  • OPB-Skills:91个AI技能模块,构建你的专属智能工作流
  • 从单一到多维:ECharts多坐标系组合的终极指南
  • OfficeCLI:重新定义AI办公自动化的下一代工具链
  • YOLT核心功能解析:车辆、建筑与机场检测一网打尽
  • 问GKG矿用开关柜生产商推荐几家重技术交付2026找金山门科技有限公司 - 热点品牌推荐
  • 本色PEEK棒批发厂家推荐怎么选深圳市鸿泰锦悦科技有限公司 - 热点品牌推荐
  • SpringBoot+Vue实习管理系统全栈开发实战
  • 如何快速配置electerm主题:5个提升终端体验的终极技巧
  • Kubeflow Pipelines技术深度解构:从开发者体验看机器学习工作流编排的实现哲学
  • Python上下文管理器:优雅实现资源管理与异常处理
  • Prime Agent框架:基于RLMF的大模型自改进技术实践指南
  • 如何为PAPermissions贡献代码?开发者指南与贡献流程详解
  • RedisInsight终极指南:5个核心功能让你告别Redis命令行烦恼
  • 上街区卫生间防水漏到楼下维修公司指南河南帅旗防水工程有限公司上街区联络处 - 热点品牌推荐
  • #戴南专业冷拔工业管供应商优选江苏巨登不锈钢管业有限公司(戴南运营中心) - 热点品牌推荐
  • Python 如何使用 MySQL 的事务
  • .NET异步监控的3个关键预警机制与实战方案
  • 别再把权限写进提示词:Agent 外部控制面的可运行设计
  • 2026年跨境电商出海必看:AI搜索生成式引擎(GEO)优化服务商大盘点,附合作避坑指南与适配选型攻略 - 商业大观
  • LunaTranslator:3步解决视觉小说语言障碍,让日文游戏无障碍畅玩
  • 资源型与技术型项目获取的核心差异与实战策略
  • 大模型应用系列:从Ranking到Reranking
  • 免费开源的键盘节奏游戏终极指南:Etterna完全体验
  • 探秘河南省建设劳动学会网站深度解析如何成为行业同仁的智慧宝库
  • 十分钟实现网页交互式几何画板:SVG+Two.js+响应式模型实战
  • 施工安全设施检测数据集 | 10600张YOLO智慧工地数据集