重定向和VT100编程

一、文件重定向

    我们知道在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\n",sizeof("abc\n")); printf("this statement can not write to stdout.\n"); 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\n",sizeof("abcdefg\n")); printf("this statement can write to stdout.\n"); 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\n",fd);
write(fd,"abcdefg\n",sizeof("abcdefg\n")); 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 码值 = '\033' ) , 通过在C程序中利用 printf
来输出VT100的指令码改变终端的样式。
    
    说了这么多,好像不得要领,因为VT100是一个非常复杂的机制,英文的介绍文档长达100多页,我们直接进行一次
体验,就能有一个感性的认识了。
 Exp:   1   在整个终端界面输出  大写的 E 字符, 指令码为  ESC #8
#include <stdio.h>

int main(void)
{
printf("\033#8");
return 0;
}
程序的执行效果如下所示:
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
[root@localhost vt100]# EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
   这样整个屏幕就输被大写的字符  E 给铺满了。
   这时候,如果在终端输入 reset 命令,就可以恢复到正常状态。或者一直按住 Enter 键直到出现正常的界面,
或者用快捷键  Ctrl + l  (小写字母 l ,不是数字1 )也可以恢复正常界面。
    
    要实现上面的效果,还可以利用 echo 命令实现:
[root@localhost vt100]# echo -ne  "\033#8"
    上面的命令同样可以实现 printf("\033#8"), 的效果。
 
    Exp:  将光标一直回退到终端的第一行、第一列。
#include <stdio.h>

int main(void)
{
for(;;)
{
printf("\033[H");
printf("0123456789abcdefghijklmnopqrstuvwxyz");
}
return 0;
}
    执行的时候,在终端窗口的最上面的第一列一直输出。  具体效果可以自己测试一下。
    上面的效果还可以用  printf("\033[1;1H");  实现;  指令码  "\033[x;yH" 表示将光标位置设置到 ( x,y )处, x,y
从1开始计数。
 
    还可以改变输出的颜色: 前景色(即字符显示颜色)和背景色。 前景、背景均支持8种颜色,设置前景色用指令码:"\033[30m"  到  "\033[37m"   ;  设置背景色用指令 "\033[40m" 到 "\033[47m" .
    前景色:
                "\033[30m"    黑色
                "\033[31m"    红色
                "\033[32m"    绿色
                "\033[33m"    黄色
                "\033[34m"    蓝色
                "\033[35m"    紫色
                "\033[36m"    深绿
                "\033[37m"    白色
 
    背景色:
                "\033[40m"    黑色
                "\033[41m"    深红
                "\033[42m"    绿色
                "\033[43m"    黄色   
                "\033[44m"    蓝色
                "\033[45m"    紫色
                "\033[46m"    深绿
                "\033[47m"    白色
 
    Exp: 改变中断的输出颜色。 main.c 
#include <stdio.h>

int main(void)
{
int i;
for(i=0;i<3;i++)
{
printf("\033[37m\033[40m");
printf("0123456789abcdefghijklmnopqrstuvwxyz\n");
printf("\033[30m\033[47m");
printf("0123456789abcdefghijklmnopqrstuvwxyz\n");
}
return 0;
}
    执行效果具体可以测试一下,为灰色和黑色交替的颜色。
                
 
 
三、系统时钟
    在linux中可以通过系统提供的函数,获取系统的时间信息; 通过time 函数族可以获取系统的时间。time函数族
的原型如下分述如下:
    time函数:
  TIME(2)                    Linux Programmer’s Manual                   TIME(2)
NAME
time - get time in seconds //获取从1970年1月1日0时0分0秒 到 当前时刻的 总秒数
SYNOPSIS
#include <time.h> time_t time(time_t *t); //输出参数,存储获取的秒
返回值:
    成功返回获取的秒, 失败返回 ((time_t)-1)  .
 
Exp:  打印从1970年1月1日0时0分0秒到现在经过了多少 秒 。
#include <stdio.h>
#include <time.h> int main(void)
{
time_t t; printf("From 1970 01-01 0:00:00 have past secnods:%ld\n", time(&t)); return 0;
}
    执行结果如下所示 :
[root@localhost time]# ./a.out
From 1970 01-01 0:00:00 have past secnods:1386835671 
    通过time函数得到的系统时钟 可读性很差,linux提供了一套转换和格式的函数来使这个时间更易读。下面一些函数
实现转换和格式的功能:
CTIME(3)                   Linux Programmer’s Manual                  CTIME(3)
NAME
asctime, ctime, gmtime, localtime, mktime, asctime_r, ctime_r, gmtime_r, local-
time_r - transform date and time to broken-down time or ASCII
SYNOPSIS
#include <time.h> char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf); char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf); struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result); time_t mktime(struct tm *tm);
    这里需要用到一个结构体类型:struct  tm ,
    其定义如下:
           struct tm {
int tm_sec; /* seconds */ //秒
int tm_min; /* minutes */ //分
int tm_hour; /* hours */ //时
int tm_mday; /* day of the month */ //一个月的第几天, 即 日
int tm_mon; /* month */ //月
int tm_year; /* year */ //年, 从1900年到现在的年数
int tm_wday; /* day of the week */ //星期几
int tm_yday; /* day in the year */ //一年中的第几天
int tm_isdst; /* daylight saving time */
};
Exp:    输出年月日  星期  时分秒
#include <stdio.h>
#include <time.h>
#include <stdlib.h> int main(void)
{
time_t t;
struct tm tm;
void* p_tmp;
char buf[32]; time(&t);
p_tmp=localtime_r(&t,&tm);
if(NULL == p_tmp)
{
perror("get local time");
exit(1);
} sprintf(buf,"%d-%d-%d %d %d-%d-%d", 1900 + tm.tm_year, 1+ tm.tm_mon,tm.tm_mday,
tm.tm_wday,
tm.tm_hour,tm.tm_min,tm.tm_sec); printf("%s\n",buf); return 0;
}
    输出结果如下:
[root@localhost time]# ./a.out
2013-12-12 4 16-30-4 //2013年11月12日 星期4 16:30:04
    需要注意的是:
          tm结构体中的年是从 1900 年到现在经过的年数, 而月的计数是从0 开始的,因此要得到年需要在 tm.tm_year
的基础上加上1900 , 月份则需要在 tm.tm_mon 的基础上加上 1 。
 
    事实上系统还提供了更加方便的格式化函数:  strftime,  其原型如下:
STRFTIME(3)                Linux Programmer’s Manual               STRFTIME(3)
NAME
strftime - format date and time SYNOPSIS
#include <time.h> size_t strftime(char *s, //存储格式化后的字符串
size_t max, //字符串的最大长度
const char *format, //格式化字符串
const struct tm *tm); //struct time 的结构体指针
返回值:
        返回写入到 char* s 的字符数, 不包括s 后的 '\0' 字符。
 
Exp:  改进后的显示  年月日  星期   时分秒 的代码
 
#include <stdio.h>
#include <time.h>
#include <stdlib.h> int main(void)
{
time_t t;
struct tm tm;
void* p_tmp;
char buf[64]; //clear screen
printf("\033[2J");
for(;;)
{
time(&t);
p_tmp=localtime_r(&t,&tm);
if(NULL == p_tmp)
{
perror("get local time");
exit(1);
} strftime(buf,64,"%Y-%m-%d %A %T %z",&tm); printf("\033[H\033[34m");
printf("%s\n",buf);
sleep(1);
}
return 0;
}
  执行结果可自己测试一下。
 
另类小技巧:
      我们知道,在linux 下,输入子系统的设备文件在  /dev/input/ 目录下。我的系统如下所示:
[root@localhost input]# ls
event0 event1 event2 event3 event4 js0 mice mouse0 mouse1 mouse2
[root@localhost input]#
    event0-event4 表示键盘设备, 键盘具体具体挂载在那一个设备节点文件上可以通过下面的测试判断出来,
通常第一个键盘挂载在 /dev/input/event0 上。
    mice: 表示鼠标设备节点文件,
    mouse0-mouse2 : 表示鼠标设备。
    js0 :   表示的游戏手柄的设备节点文件。
 
     可以测试一下:   cat  /dev/input/event0     然后敲下键盘输入字符,Ctrl + c,如果出现乱码不能恢复,那
                                                                    么在终端输入 reset 命令即可恢复, 输入reset 时看到的还是乱
                                                                    码, 或者输入: echo   -ne  "\033["
                                                                             
                                 cat  /dev/input/mice        然后移动鼠标,会看到一些出现乱码
     如果想结束测试:  按下  Ctrl + c
 
  【Linux草鞋应用编程系列】_6_重定向和VT100编程 
   欢迎批评指正,也欢迎拍砖。
   本系列文章,未完待续......

  【linux草鞋应用编程系列】_5_ Linux网络编程

 
 
标签: linuxC应用编程

重定向和VT100编程的更多相关文章

  1. 【linux草鞋应用编程系列】_6_ 重定向和VT100编程

    一.文件重定向     我们知道在linux shell 编程的时候,可以使用文件重定向功能,如下所示: [root@localhost pipe]# echo "hello world&q ...

  2. 详解Win2003 IIS6.0 301重定向带参数的问题(转摘)

      网站更换域名,把旧域名用301指到新域名来. 从iis中设置url永久转向就可以,看上去很容易,用了一会儿才发现,参数都没有带上. 从微软网站上找到如下说明,果然好使: 重定向参考 (IIS 6. ...

  3. Intel 80x86 Linux Kernel Interrupt(中断)、Interrupt Priority、Interrupt nesting、Prohibit Things Whthin CPU In The Interrupt Off State

    目录 . 引言 . Linux 中断的概念 . 中断处理流程 . Linux 中断相关的源代码分析 . Linux 硬件中断 . Linux 软中断 . 中断优先级 . CPU在关中断状态下编程要注意 ...

  4. 【转载】应读者强烈要求给出《超容易的Linux系统管理入门书》一书的主要知识点

    刚开始了一篇连载,收到广大Linux爱好者的反馈,非常欣慰.大家对Linux学习感到很迷茫,不知道学哪些内容,如何学习? <超容易的Linux系统管理入门书>一书是腾讯Linux专家在腾讯 ...

  5. Webfrom基础知识

    MyBeNASP.NET内置对象 (1)简述ASP.NET内置对象. 答:ASP.NET提供了内置对象有Page.Request.Response.Application.Session.Server ...

  6. 如何利用 LTE/4G 伪基站+GSM 中间人攻击攻破所有短信验证

    这次公开课请来的嘉宾对自己的简介是: 连续创业失败的创业导师:伪天使投资人:某非知名私立大学创办人兼校长:业余时间在本校通信安全实验室打杂. 自从他在黑客大会上演讲<伪基站高级利用技术——彻底攻 ...

  7. webConfig详细跳转配置.[转]

    站更换域名,把旧域名用301指到新域名来. 从iis中设置url永久转向就可以,看上去很容易,用了一会儿才发现,参数都没有带上. 从微软网站上找到如下说明,果然好使: 重定向参考 (IIS 6.0,7 ...

  8. 2019-2020-1 20199302《Linux内核原理与分析》第八周作业

    一.上课学习笔记 1.shell作用:①运行程序 ②重定向(输入/输出重定向) ③可编程(写脚本) 执行一个c程序时,如果切进另一个进程,会进入该进程而切不回原进程,所以需要为调用的进程创一个子进程. ...

  9. 请求转发:MVC设计模式、细节、请求域属性的编程实例、请求重定向和请求转发的区别

      请求转发:MVC设计模式.细节.请求域属性的编程实例.请求重定向和请求转发的区别 MVC设计模式将一次请求的响应过程分成三个功能模块(一般称之为层)来协同完成,这三个模块分别是Model(模型层) ...

随机推荐

  1. osx launchpad删除图标

    安装了个parallels desktop之后,OSX中的launchpad中的图标多了不少,但是好多都不是我自己想要的,我们该怎么删除或者改动呢,以下介绍一些方法: ①直接操作Appications ...

  2. Flex列在一个表格式的数字值

    1.问题背景 一般的.表格中展示的比率.对照率的处理是:保留两位小数,并向上保留 2.实现实例 <? xml version="1.0" encoding="utf ...

  3. KafkaOffsetMonitor

    Kafka实战-KafkaOffsetMonitor   1.概述 前面给大家介绍了Kafka的背景以及一些应用场景,并附带上演示了Kafka的简单示例.然后,在开发的过程当中,我们会发现一些问题,那 ...

  4. jsmart 前结合案例

    前绑定jsmart这是一个不错的选择.之前通过经常使用的项目中的.最近涉及的领域的后端部.jsmart有些使用相对较少,主要是因为他想引用文件,我写的模板,在一个简单的项目,直接使用js界,很复杂的前 ...

  5. BNUOJ 34981 A Matrix

    BNUOJ 34981 A Matrix 题目地址:pid=34981" style="color:rgb(0,136,204); text-decoration:none&quo ...

  6. WebService返回DataTable问题

    今天做项目时,想在WebService中返回DataTable,在单位没成功,看网上有人说datable在.net1.1中是没有序列化的,不能直接在webservice中返回,可以返回dataset. ...

  7. JAVA 长整型转换为IP地址的方法

    JAVA 长整型转换为IP地址的方法 代码例如以下: /** * 整型解析为IP地址 * @param num * @return */ public static String int2iP(Lon ...

  8. ASP.NET 5:依赖注入

    ASP.NET 5:依赖注入 1.背景 如果某个具体的(或类)对象被客户程序所依赖,通常把它们抽象成抽象类或接口.简单说,客户程序摆脱所依赖的具体类型,称之为面向接口编程. 那么问题来了?如何选择客户 ...

  9. 湘潭oj1203/邀请赛A称号 数论+java睑板

    乞讨 n%1+n%2+n%3+n%4+.........n%n=,n<=10^12次要. 一味的找规律之初.没有发现.后来,前辈执教后,人才平淡,所以,现在唯一明确的. 首先在地图上: 对于该题 ...

  10. Python_生成測试数据

    本文出自:http://blog.csdn.net/svitter 生成1~10的随机数1000个: import random fp = open("test", 'w'); f ...