在C语言中使用伪终端与bash交互
- 了解伪终端概念:
- 伪终端(PTY)由一对设备组成:主设备(master)和从设备(slave)。数据写入主设备会出现在从设备,反之亦然。这允许一个进程通过主设备与另一个进程(如
bash
)通过从设备进行通信。
- 伪终端(PTY)由一对设备组成:主设备(master)和从设备(slave)。数据写入主设备会出现在从设备,反之亦然。这允许一个进程通过主设备与另一个进程(如
- 相关函数:
openpty
:用于创建伪终端对。其原型为int openpty(int *amaster, int *aslave, char *name, const struct termios *termp, const struct winsize *winp)
。amaster
和aslave
是指向文件描述符的指针,分别用于主设备和从设备;name
可用于获取从设备的路径名;termp
可用于设置终端属性;winp
可用于设置窗口大小。fork
:创建一个新进程,子进程通常用于执行bash
,父进程用于与伪终端主设备交互。dup2
:在子进程中用于将标准输入、输出和错误重定向到伪终端从设备。write
和read
:用于在父进程中向伪终端主设备写入命令,并读取bash
的输出。
- 示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <string.h>
#define BUFFER_SIZE 1024
// 设置文件描述符为非阻塞模式
void set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
int main() {
int master, slave;
pid_t pid;
char buffer[BUFFER_SIZE];
struct termios oldtty, newtty;
// 创建伪终端对
if (openpty(&master, &slave, NULL, NULL, NULL) == -1) {
perror("openpty");
return 1;
}
// 保存当前终端设置
tcgetattr(STDIN_FILENO, &oldtty);
newtty = oldtty;
// 设置终端为非规范模式
newtty.c_lflag &= ~(ICANON | ECHO);
// 设置终端属性
tcsetattr(STDIN_FILENO, TCSANOW, &newtty);
// 设置伪终端主设备为非阻塞模式
set_nonblocking(master);
// 创建子进程
pid = fork();
if (pid == -1) {
perror("fork");
close(master);
close(slave);
return 1;
} else if (pid == 0) {
// 子进程
close(master);
// 将标准输入、输出和错误重定向到伪终端从设备
if (dup2(slave, STDIN_FILENO) == -1) {
perror("dup2 stdin");
return 1;
}
if (dup2(slave, STDOUT_FILENO) == -1) {
perror("dup2 stdout");
return 1;
}
if (dup2(slave, STDERR_FILENO) == -1) {
perror("dup2 stderr");
return 1;
}
close(slave);
// 启动bash
execl("/bin/bash", "bash", (char *)NULL);
perror("execl");
return 1;
} else {
// 父进程
close(slave);
// 向bash发送命令
const char *command = "ls\n";
if (write(master, command, strlen(command))!= strlen(command)) {
perror("write");
}
// 读取bash的输出
ssize_t bytes_read;
while ((bytes_read = read(master, buffer, sizeof(buffer) - 1)) > 0) {
buffer[bytes_read] = '\0';
printf("%s", buffer);
}
// 等待子进程结束
waitpid(pid, NULL, 0);
// 恢复终端设置
tcsetattr(STDIN_FILENO, TCSANOW, &oldtty);
close(master);
}
return 0;
}
- 代码解释:
- 创建伪终端对:使用
openpty
创建伪终端主设备master
和从设备slave
。 - 终端设置:保存当前终端设置
oldtty
,并修改为非规范模式newtty
,这样可以实时读取输入而无需等待换行符。 - 设置非阻塞模式:将伪终端主设备设置为非阻塞模式,以便在读取输出时不会阻塞。
- 进程创建:通过
fork
创建子进程,子进程执行bash
,父进程与伪终端主设备交互。 - 子进程操作:关闭
master
,将标准输入、输出和错误重定向到slave
,然后执行bash
。 - 父进程操作:关闭
slave
,向master
写入命令(如ls\n
),循环读取并打印bash
的输出,等待子进程结束,最后恢复终端设置。
- 创建伪终端对:使用
这样,通过上述代码,你可以在C语言程序中使用伪终端与bash
进行交互。