APUE 第3版第15页的shell2.c示例程序,运行效果如下:

 gcc ol.shell.c -o origin_shell

 ./origin_shell
% date
2015年12月13日 星期日 22时04分48秒 CST
% ^Cinterrupt
ls
Makefile getcputc.c mycat.c myls_info.c note.md origin_shell shell2.c uidgid.c
a.out hello.c myls.c myls_sort.c ol.shell.c shell1.c testerror.c
% %
couldn't execute: : No such file or directory
% ls
Makefile getcputc.c mycat.c myls_info.c note.md origin_shell shell2.c uidgid.c
a.out hello.c myls.c myls_sort.c ol.shell.c shell1.c testerror.c
%

从上述示例中可以看出,存在2个小问题:

1. 当通过ctrl+C输入中断信号时,中断捕获程序的输出语句的“%”并没有立即输出来,等到下一次回车时才输出,导致第10行有两个%%号。

2. 当出现%提示符时,直接回车,会提示如11行所示的错误。因为此时传递给execlp函数的buf内容是空的。其中问题1是出现在程序中的如下一句:

while (fgets(buf, MAXLINE, stdin) != NULL) {
}
// 即中断信号中断的是fgets函数,此时系统正在请求输入中,而中断处理程序的输出: printf("interrupt\n%% "); // 在换行之后,%并没有立即出来。如果将其修改如下, printf("interrupt\n%%\n");
// 则显示效果变成这样:
 % ^Cinterrupt
%
ls
Makefile mycat.c note.md shell2.c
a.out myls.c ol.shell.c testerror.c
getcputc.c myls_info.c origin_shell uidgid.c
hello.c myls_sort.c shell1.c

如上可见,上述增加一个'\n'后,虽然立即输出了%,但如第3行所见,光标移到%下一行了。

一个解决办法是使用fflush()函数。完整代码,新增为21-24行,以及46行:

 #include "../apue.h"
#include <sys/wait.h> static void sig_int(int); /* our signal-catching function */ int
main(void)
{
char buf[MAXLINE]; /* from apue.h */
pid_t pid;
int status; if (signal(SIGINT, sig_int) == SIG_ERR)
err_sys("signal error"); printf("%% "); /* print prompt (printf requires %% to print %) */
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf) - ] == '\n')
buf[strlen(buf) - ] = ; /* replace newline with null */ if (strlen(buf) == ) { // 此if语句用于处理直接回车
printf("%% ");
continue;
} if ((pid = fork()) < ) {
err_sys("fork error");
} else if (pid == ) { /* child */
execlp(buf, buf, (char *));
err_ret("couldn't execute: %s", buf);
exit();
} /* parent */
if ((pid = waitpid(pid, &status, )) < )
err_sys("waitpid error");
printf("%% ");
}
exit();
} void
sig_int(int signo)
{
printf(" interrupt!\n%%");
fflush(stdout); //强制输出所有stdout中的字符流
}

完善后效果如下:

 % date
2015年12月13日 星期日 22时31分53秒 CST
% ^C interrupt!
% date
2015年12月13日 星期日 22时32分15秒 CST
%
%

APUE fig 1.10示例代码的完善--对提示符及输入回车的优化的更多相关文章

  1. redis 学习笔记(2)-client端示例代码

    redis提供了几乎所有主流语言的client,java中主要使用二种:Jedis与Redisson 一.Jedis的使用 <dependency> <groupId>redi ...

  2. c# 使用hook来监控鼠标键盘事件的示例代码

    如果这个程序在10几年前,QQ刚刚兴起的时候,有了这个代码,就可实现盗号了. 当然使用钩子我们更多的是实现"全局快捷键"的需求. 比如 程序最小化隐藏后要"某快捷键&qu ...

  3. Ajax原理,技术封装与完整示例代码

    在做项目和学习的时候,经常用到Ajax的相关技术,但是这方面的技术总是运用的不是十分好,就寻找相关博客来学习加深Ajax技术相关. 一.Ajax简介 二.同步.异步传输区别 2.1 异步传输 2.2 ...

  4. ActiveMQ笔记(1):编译、安装、示例代码

    一.编译 虽然ActiveMQ提供了发布版本,但是建议同学们自己下载源代码编译,以后万一有坑,还可以尝试自己改改源码. 1.1 https://github.com/apache/activemq/r ...

  5. php示例代码之类似于C#中的String.Format方法

    php示例代码之类似于C#中的String.Format方法 原文来自于  http://stackoverflow.com/questions/1241177/c-string-format-equ ...

  6. C# 6新特性及示例代码

    今天推荐的其实是一个Github开源项目,不过这个开源项目是专门介绍C# 6的最新特性,并给出了示例代码. 我们知道,微软即将发布Windows 10和Visual Studio 2015,在VS20 ...

  7. C# WebSocket 服务端示例代码 + HTML5客户端示例代码

    WebSocket服务端 C#示例代码 using System; using System.Collections.Generic; using System.Linq; using System. ...

  8. Swift常用语法示例代码(二)

    此篇文章整理自我以前学习Swift时的一些练习代码,其存在的意义多是可以通过看示例代码更快地回忆Swift的主要语法. 如果你想系统学习Swift或者是Swift的初学者请绕路,感谢Github上Th ...

  9. Swift常用语法示例代码(一)

    此篇文章整理自我以前学习Swift时的一些练习代码,其存在的意义多是可以通过看示例代码更快地回忆Swift的主要语法. 如果你想系统学习Swift或者是Swift的初学者请绕路,感谢Github上Th ...

随机推荐

  1. Sql Server系列:分区表操作

    1. 分区表简介 分区表在逻辑上是一个表,而物理上是多个表.从用户角度来看,分区表和普通表是一样的.使用分区表的主要目的是为改善大型表以及具有多个访问模式的表的可伸缩性和可管理性. 分区表是把数据按设 ...

  2. SQL Server中的高可用性(2)----文件与文件组

        在谈到SQL Server的高可用性之前,我们首先要谈一谈单实例的高可用性.在单实例的高可用性中,不可忽略的就是文件和文件组的高可用性.SQL Server允许在某些文件损坏或离线的情况下,允 ...

  3. 通过adb方式给安卓手机截图的cmd批处理文件

    @echo off rem  通过adb方式截图rem  需要安装adb ,一般安装了android sdk 默认带了adb ,路径为sdk目录的android-sdk\platform-toolsr ...

  4. 关于ubuntu实机与虚机互相copy

    我的开发环境是在ubuntu上的,但是ubuntu上没有官方支持的QQ,有些不太方便,所以在上面虚了一个Win7(先是win10,但是win10最新版本太坑了,不说了),不过经常会出现复制文件,或者文 ...

  5. C# i=0;i=i++,i的值是多少?

    昨天看群里dalao们聊天,有一个人出来问这个问题 这个题应该是挺常见的 int i = 0, t;        for(t = 0;t <= 5;t++)        {          ...

  6. MySQL碎碎念

    1. 如何修改Mysql的用户密码 mysql> update mysql.user set password=password('hello') where user='root'; mysq ...

  7. 在Asp.Net中操作PDF – iTextSharp - 使用表格

    使用Asp.Net生成PDF最常用的元素应该是表格,表格可以帮助比如订单或者发票类型的文档更加格式化和美观.本篇文章并不会深入探讨表格,仅仅是提供一个使用iTextSharp生成表格的方法介绍 使用i ...

  8. 小兔JS教程(三)-- 彻底攻略JS回调函数

    这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...

  9. java设计模式之--单例模式

    前言:最近看完<java多线程编程核心技术>一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持. 单例模 ...

  10. 满堂红CIO邓劲翔:房屋中介突围

    人脸识别.客户关系管理进度监控.业务流程实时监控.网站访问人数及流量实时监控等实际企业应用场景淋漓尽致.羽羽如生的以大屏幕上图表形式展现在人们面前,如果你不去继续询问,你不会知道这是一家才刚刚在房地产 ...