如何通过execvp系统调用执行带重定向的ls>file.txt命令
基于execvp实现标准输出重定向的核心逻辑
核心前提:execvp本身完全不支持shell语法解析,根本没法直接接收带ls > file.txt这类重定向操作的输入
为什么不能直接把带重定向的命令拆给execvp
- execvp的原生职责是在系统PATH路径中匹配查找对应可执行文件,将传入的参数数组原样作为目标程序的启动参数,替换当前进程的运行空间
- 它对shell层面定义的重定向符号(
>、<、>>、2>等)没有任何处理逻辑,如果把>、file.txt这类字符串塞进参数数组传给execvp,ls会将这两个内容当成自己的普通命令行参数,最终会抛出类似ls: cannot access '>': No such file or directory的报错
实现ls > file.txt的完整执行流程
整个流程的核心逻辑是:重定向操作完全由你自己的shell代码在调用execvp之前完成,execvp只负责纯粹执行无语法符号的目标命令
- 第一步:完成输入命令的语法拆分,把原始输入拆成三类独立内容:
- 待执行的可执行程序名:
ls - 传给程序的纯参数数组:按标准execvp入参要求,数组第一个元素为程序名本身,以NULL结尾,比如不带额外参数的ls对应数组为
{"ls", NULL},如果是带-l参数的ls,对应数组为{"ls", "-l", NULL} - 重定向规则配置:标准输出(文件描述符STDOUT_FILENO,也就是1号fd)需要被定向到目标文件
file.txt
- 待执行的可执行程序名:
- 第二步:在fork出的子进程中(不要在父进程做,避免把shell自身的标准输出改掉),在调用execvp之前完成重定向绑定
- 用
open("file.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644)打开目标文件:参数含义是文件不存在则创建、已存在则清空内容、文件权限设为普通用户可读写,调用后会得到一个指向file.txt的文件描述符 - 调用
dup2()系统调用,把刚才打开的文件描述符,复制覆盖到标准输出的文件描述符上,即执行dup2(file_fd, STDOUT_FILENO)——执行完这步后,当前进程所有往标准输出写的内容,都会直接写入file.txt,不会再输出到终端 - 调用
close(file_fd)关掉open拿到的原始文件描述符,因为dup2已经完成了文件描述符的绑定,这个多余的fd不会影响后续操作
- 用
- 第三步:调用execvp执行目标程序
- 传入的参数是刚才整理好的、完全不带重定向符号的纯ls参数数组,即
execvp("ls", ls_args) - 此时ls运行时完全感知不到自己的输出流被修改了,它还是按固有逻辑往1号fd写内容,而1号fd已经被提前绑定到file.txt,自然就实现了标准输出重定向的效果
- 传入的参数是刚才整理好的、完全不带重定向符号的纯ls参数数组,即
常见踩坑提示
- 绝对不要把重定向符号作为参数传给execvp,这是最常见的新手错误
- 所有重定向操作必须放在execvp调用之前完成,execvp一旦执行成功,当前进程的代码段就会被目标程序替换,后续写的所有自定义shell逻辑都不会再运行
- 其他类型的重定向(比如追加写入的
>>、标准错误重定向的2>、标准输入重定向的<)都是完全相同的实现逻辑,只需要在open时调整对应的打开flag,用dup2替换对应的标准流fd即可
内容的提问来源于stack exchange,提问作者Sannan Yousuf
相关产品推荐
相关产品推荐

