一、文件重定向
我们知道在linux shell 编程的时候,可以使用文件重定向功能,如下所示:
[root@localhost pipe]# echo "hello world" hello world //没有进行重定向,在终端显示 [root@localhost pipe]# echo "hello world" > txt //进行重定向,不在终端显示 [root@localhost pipe]# cat txt //查看生成的文件 txt 的内容 hello world [root@localhost pipe]#
在linux系统中,通过复制文件描述符实现文件的重定向。
1、复制文件描述符
linux系统中,通过函数 dup( ) 和 dup2()两个函数实现文件描述符的复制。 其原型如下:
DUP(2) Linux Programmer’s Manual DUP(2) NAME dup, dup2 - duplicate a file descriptor //复制文件描述符 SYNOPSIS #include <unistd.h> int dup(int oldfd); //要被替代掉的文件描述符, 旧文件描述符 int dup2(int oldfd, //要被替代掉的文件描述符, 旧文件描述符 int newfd); //替代的文件描述符, 新文件描述符
返回值:
成功返回新的文件描述符, 失败返回-1 。
下面我们实现一个程序,就是将标准输出设备进行重定向, 即实现 类似于 shell 中 > 的功能。
Exp: 如何将文件描述符进行定向 main.c
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> int main(int argc,char* argv[]) { int fd; fd=open(argv[1], O_RDWR|O_CREAT, 0666); if(-1 == fd ) { perror("open"); exit(1); } fd=dup2(fd,1); //将 fd 指向了 stdout , 即将 stdout 重定向到了 fd 描述的文件 if(-1 == fd) { perror("dup2"); exit(1); } write(1,"abc ",sizeof("abc ")); printf("this statement can not write to stdout. "); close(fd); return 0; }
程序的执行过程如下:
[root@localhost redirectory]# ll 总计 12 -rwxr-xr-x 1 root root 5436 12-12 14:18 a.out -rw-r--r-- 1 root root 468 12-12 14:18 main.c [root@localhost redirectory]# ./a.out txt //可以看到 printf函数没有输出,而通过 write(1,xx,xx) 的信息也没有输出到stdout [root@localhost redirectory]# cat txt //数据写入到了txt, 查看txt 的内容 abc [root@localhost redirectory]#
上面的执行结果,说明我们将标准输出重定向到了 fd 描述的文件 txt. 同时也说明了在重定向 stdout 后,printf
函数也不会将数据输出标准输出,或者重定向后的文件。
为了对比我们进行一下改变, 修改后的 main.c :
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> int main(int argc,char* argv[]) { int fd; fd=open(argv[1], O_RDWR|O_CREAT, 0666); if(-1 == fd ) { perror("open"); exit(1); } #if 0 fd=dup2(fd,1); if(-1 == fd) { perror("dup2"); exit(1); } #endif write(1,"abcdefg ",sizeof("abcdefg ")); printf("this statement can write to stdout. "); close(fd); return 0; }
执行结果如下:
[root@localhost redirectory]# vim main.c [root@localhost redirectory]# gcc main.c [root@localhost redirectory]# cat txt abc [root@localhost redirectory]# ./a.out txt abcdefg //write(1,xx,xx) 正常从标准输出输出 this statement can write to stdout. //printf 也正常输出到标准输出 [root@localhost redirectory]# cat txt abc [root@localhost redirectory]#
dup函数不能实现重定向,只是实现分配一个新的文件描述符。
Exp:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> int main(int argc,char* argv[]) { int fd; fd=dup(1); printf("the new fd is: %d ",fd); write(fd,"abcdefg ",sizeof("abcdefg ")); close(fd); return 0; }
程序的执行过程如下:
[root@localhost redirectory]# vim dup.c [root@localhost redirectory]# gcc dup.c [root@localhost redirectory]# ./a.out the new fd is: 3 //默认dup()成功返回最小的未分配的文件描述符 abcdefg //通过fd, 实现了对 stdout = 1 标准输出的写操作 [root@localhost redirectory]#
二、VT 100 编程
在linux中可以通过 VT100 码对终端进行设置,要设置终端,让 printf 输出VT100 指令码就可以实现。VT100控制
指令码英语的原文为: ESC sequences 。 翻译成指令码、控制码都好像不能完整的表述其意义;我们这里用指令码对
来指代上面的: ESC sequences 。
VT100 终端控制机制的指令码都以 ESC 的ASCII开始(ESC 字符的 ASCII 码值 = ' 33' ) , 通过在C程序中利用 printf
来输出VT100的指令码改变终端的样式。
说了这么多,好像不得要领,因为VT100是一个非常复杂的机制,英文的介绍文档长达100多页,我们直接进行一次
体验,就能有一个感性的认识了。
Exp: 1 在整个终端界面输出 大写的 E 字符, 指令码为 ESC #8
#include <stdio.h> int main(void) { printf("