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

  1. gcc ol.shell.c -o origin_shell
  2.  
  3. ./origin_shell
  4. % date
  5. 20151213 星期日 220448 CST
  6. % ^Cinterrupt
  7. ls
  8. Makefile getcputc.c mycat.c myls_info.c note.md origin_shell shell2.c uidgid.c
  9. a.out hello.c myls.c myls_sort.c ol.shell.c shell1.c testerror.c
  10. % %
  11. couldn't execute: : No such file or directory
  12. % ls
  13. Makefile getcputc.c mycat.c myls_info.c note.md origin_shell shell2.c uidgid.c
  14. a.out hello.c myls.c myls_sort.c ol.shell.c shell1.c testerror.c
  15. %

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

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

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

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

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

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

  1. #include "../apue.h"
  2. #include <sys/wait.h>
  3.  
  4. static void sig_int(int); /* our signal-catching function */
  5.  
  6. int
  7. main(void)
  8. {
  9. char buf[MAXLINE]; /* from apue.h */
  10. pid_t pid;
  11. int status;
  12.  
  13. if (signal(SIGINT, sig_int) == SIG_ERR)
  14. err_sys("signal error");
  15.  
  16. printf("%% "); /* print prompt (printf requires %% to print %) */
  17. while (fgets(buf, MAXLINE, stdin) != NULL) {
  18. if (buf[strlen(buf) - ] == '\n')
  19. buf[strlen(buf) - ] = ; /* replace newline with null */
  20.  
  21. if (strlen(buf) == ) { // 此if语句用于处理直接回车
  22. printf("%% ");
  23. continue;
  24. }
  25.  
  26. if ((pid = fork()) < ) {
  27. err_sys("fork error");
  28. } else if (pid == ) { /* child */
  29. execlp(buf, buf, (char *));
  30. err_ret("couldn't execute: %s", buf);
  31. exit();
  32. }
  33.  
  34. /* parent */
  35. if ((pid = waitpid(pid, &status, )) < )
  36. err_sys("waitpid error");
  37. printf("%% ");
  38. }
  39. exit();
  40. }
  41.  
  42. void
  43. sig_int(int signo)
  44. {
  45. printf(" interrupt!\n%%");
  46. fflush(stdout); //强制输出所有stdout中的字符流
  47. }

完善后效果如下:

  1. % date
  2. 20151213 星期日 223153 CST
  3. % ^C interrupt!
  4. % date
  5. 20151213 星期日 223215 CST
  6. %
  7. %

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. In-Memory:在内存中创建临时表和表变量

    在Disk-Base数据库中,由于临时表和表变量的数据存储在tempdb中,如果系统频繁地创建和更新临时表和表变量,大量的IO操作集中在tempdb中,tempdb很可能成为系统性能的瓶颈.在SQL ...

  2. 【.net 深呼吸】细说CodeDom(5):类型成员

    前文中,老周已经厚着脸皮介绍了类型的声明,类型里面包含的自然就是类型成员了,故,顺着这个思路,今天咱们就了解一下如何向类型添加成员. 咱们都知道,常见的类型成员,比如字段.属性.方法.事件.表示代码成 ...

  3. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  4. Swift与C#的基础语法比较

    背景: 这两天不小心看了一下Swift的基础语法,感觉既然看了,还是写一下笔记,留个痕迹~ 总体而言,感觉Swift是一种前后端多种语言混合的产物~~~ 做为一名.NET阵营人士,少少多多总喜欢通过对 ...

  5. 通过ProGet搭建一个内部的Nuget服务器

    .NET Core项目完全使用Nuget 管理组件之间的依赖关系,Nuget已经成为.NET 生态系统中不可或缺的一个组件,从项目角度,将项目中各种组件的引用统统交给NuGet,添加组件/删除组件/以 ...

  6. bootstrap + requireJS+ director+ knockout + web API = 一个时髦的单页程序

    也许单页程序(Single Page Application)并不是什么时髦的玩意,像Gmail在很早之前就已经在使用这种模式.通常的说法是它通过避免页面刷新大大提高了网站的响应性,像操作桌面应用程序 ...

  7. CorelDRAW X8 如何破解激活(附国际版安装包+激活工具) 2016-12-15

    之前有位搞平面的好友“小瘦”说CDR X8无法破解,只能用X7.呃……呃……呃……好像是的 其实CDR8难激活主要在于一个点“没有离线激活了,只可以在线激活”,逆天不是专供逆向的,当然没能力去破解,这 ...

  8. 【翻译】MongoDB指南/CRUD操作(四)

    [原文地址]https://docs.mongodb.com/manual/ CRUD操作(四) 1 查询方案(Query Plans) MongoDB 查询优化程序处理查询并且针对给定可利用的索引选 ...

  9. 快速搭建springmvc+spring data jpa工程

    一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...

  10. log4net使用手册

    1. log4net简介 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.Java平台下,它还 ...