如何在C语言exec()创建的Bash中执行命令?含ls输入方法
解答:在C语言启动的Bash环境中执行命令 & 向登录Shell发送输入
1. 如何在通过exec()创建的Bash环境中执行命令?
有几种实用方式,取决于你是想让Bash执行命令后直接退出,还是启动交互式Shell再动态喂命令:
方式一:直接让Bash执行指定命令(非交互式)
这是最省心的方式——通过bash -c参数直接传递要执行的命令,Bash启动后会立刻执行该命令,完成后自动退出。比如:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> int main() { if (fork() == 0) { // 执行ls + 打印当前目录的组合命令,完成后Bash退出 execlp("bash", "bash", "-c", "ls -l && pwd", NULL); perror("execlp failed"); exit(EXIT_FAILURE); } wait(NULL); return 0; }
这里-c参数告诉Bash:后面的字符串是要执行的命令脚本,你可以用&&(成功后执行)或;(顺序执行)拼接多个命令。
方式二:给交互式Bash喂输入(适合保留Shell环境的场景)
如果你启动的是交互式Shell(比如bash -l登录Shell),需要通过重定向标准输入的方式给它发送命令,常用两种方法:
- 重定向到预先写好命令的文件:
execlp("bash", "bash", "-l", "<", "commands.txt", NULL);,文件里每行放一个要执行的命令。 - 使用管道(pipe)在父进程中动态发送命令——这也是解决你第二个问题的核心方案。
2. 向bash -l登录Shell发送ls命令作为输入
你当前的代码只重定向了标准输出,但要给Shell发输入,需要把它的标准输入(stdin)连接到一个可写入的通道,管道是最合适的选择。下面是修改后的完整可运行代码:
#include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> int main() { int pipefd[2]; // 打开用于保存Shell输出的文件 int fileDescriptor = open("bash_output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fileDescriptor == -1) { perror("Failed to open output file"); exit(EXIT_FAILURE); } // 创建管道:pipefd[0]是读端,pipefd[1]是写端 if (pipe(pipefd) == -1) { perror("Failed to create pipe"); exit(EXIT_FAILURE); } pid_t pid = fork(); if (pid == -1) { perror("Fork failed"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:配置Shell的输入输出 dup2(fileDescriptor, 1); // 重定向stdout到文件 close(fileDescriptor); dup2(pipefd[0], 0); // 重定向stdin到管道读端 close(pipefd[0]); close(pipefd[1]); // 子进程不需要写端,关闭避免资源泄漏 // 启动登录Shell execlp("bash", "bash", "-l", NULL); // 如果走到这里说明execlp失败 perror("Failed to start bash"); exit(EXIT_FAILURE); } else { // 父进程:发送命令给Shell close(pipefd[0]); // 父进程不需要读端,关闭 // 发送ls命令,必须加换行符——Bash需要换行来确认执行 const char* ls_cmd = "ls\n"; write(pipefd[1], ls_cmd, strlen(ls_cmd)); close(pipefd[1]); // 关闭写端,让Bash知道输入结束,否则会一直等待 // 等待子进程执行完毕 wait(NULL); close(fileDescriptor); } return 0; }
关键细节说明:
- 管道的作用:管道是父子进程间的单向通信通道,父进程写命令到管道写端,子进程的Shell从管道读端读取输入。
- 换行符的必要性:Bash作为交互式Shell,需要看到换行符才会执行输入的命令,所以要发送
"ls\n"而不是"ls"。 - 关闭多余文件描述符:管道两端的文件描述符在不用时必须关闭,否则Shell会一直阻塞在等待输入的状态,无法正常退出。
内容的提问来源于stack exchange,提问作者Reshmi Das
相关产品推荐
相关产品推荐

