linux系统编程综合练习-实现一个小型的shell程序(四)
#include "execute.h"
#include "def.h"
#include "externs.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/limits.h>
#include <fcntl.h> void forkexec(int i){
pid_t pid;
pid = fork();
if(pid == -) {
/* 创建进程失败了 */
ERR_EXIT("fork");
} if(pid > ) {
/* 父进程 */
if (backgnd == )
printf("%d\n", pid);
lastpid = pid;
} else if(pid == ) {
/* 子进程 */ /* 表示将第一条简单命令的infd重定向至/dev/null,其中cmd[i].infd == 0只有可能是第一条简单命令 */
/* 当第一条命令试图从标准输入获取数据的时候立既返回EOF */
if(cmd[i].infd == && backgnd == ){
//屏蔽后台作业,因为没有实现作业控制
cmd[i].infd = open("/dev/null", O_RDONLY);
} /* 将第一个简单命令进程作为进程组组长 */
if(i == ){
setpgid(, );
}
if(cmd[i].infd != ){
//说明该命令的输入是指向管道的读端
close();
dup(cmd[i].infd);
}
if(cmd[i].outfd != ){
//说明该命令的输出指向的是管道的写端
close();
dup(cmd[i].outfd);
}
/* 关闭3以上的所有文件描述符 */
/*int i;
for(i=3; i<OPEN_MAX; ++i){
close(i);
}*/ /*前台作业能够接收SIGINT,SIGQUIT信号,这两个信号就要恢复成默认操作*/
if(backgnd == ){//非后台作业
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
} /* 开始替换进程 */
execvp(cmd[i].args[], cmd[i].args);
/* 如果执行到这句,则证明替换失败了 */
exit(EXIT_FAILURE);
}
} int execute_disk_command(void){
/* ls | grep init | wc -w */
if(cmd_count == ) {
return ;
}
if(infile[] != '\0'){
cmd[].infd = open(infile, O_RDONLY);
} if(outfile[] != '\0'){
if(append)//说明是以追加的方式
cmd[cmd_count-].outfd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, );
else
cmd[cmd_count-].outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, );
} /* 因为后台作业不会调用wait等待子进程退出,为避免僵尸进程,可以忽略SIGCHLD信号 */
if(backgnd == ){
signal(SIGCHLD, SIG_IGN);
}else{
signal(SIGCHLD, SIG_DFL);
}
int i;
/* 管道描述符 */
int fds[];
int fd;
for(i=; i<cmd_count; ++i){
/* 如果不是最后一条命令,则需要创建管道 */
if(i < cmd_count-){
pipe(fds);
/* 第一条命令的输出不再是标准输出,而是管道的写端 */
cmd[i].outfd = fds[];
/* 第二条命令的输入不再是标准输入,而是管道的读端 */
cmd[i+].infd = fds[];
} /* 创建一个进程,并且替换成系统命令 */
forkexec(i); if((fd = cmd[i].infd) != )
close(fd);
if((fd = cmd[i].outfd) != )
close(fd);
} if(backgnd == ){//如果是非后台作业
while(wait(NULL) != lastpid)
;
}
}
将其forkexec函数也抽取到execute.c文件中,下面来进行编译一下:
另外在编译成,需要修改一下Makefile:
#include "builtin.h"
#include "parse.h"
#include "externs.h"
#include <stdlib.h>
#include <stdio.h> typedef void (*CMD_HANDLER)(void); typedef struct builtin_cmd
{
char *name;
CMD_HANDLER handler; } BUILTIN_CMD; void do_exit(void);
void do_cd(void);
void do_type(void); BUILTIN_CMD builtins[] =
{
{"exit", do_exit},
{"cd", do_cd},
{"type", do_type},
{NULL, NULL}
}; /*
* 内部命令解析
* 返回1表示为内部命令,0表示不是内部命令
*/
int builtin(void)
{
/*
if (check("exit"))
do_exit();
else if (check("cd"))
do_cd();
else
return 0; return 1;
*/ int i = ;
int found = ;
while (builtins[i].name != NULL)
{
if (check(builtins[i].name))
{
builtins[i].handler();
found = ;
break;
}
i++;
} return found;
} void do_exit(void)
{
printf("exit\n");
exit(EXIT_SUCCESS);
} void do_cd(void)
{
printf("do_cd ... \n");
} void do_type(void)
{
printf("do_type ... \n");
}
编译运行:
linux系统编程综合练习-实现一个小型的shell程序(四)的更多相关文章
- linux系统编程综合练习-实现一个小型的shell程序(一)
之前已经花了不少篇幅学习了linux系统编程的很多知识点:文件与io.进程.信号.管道,而零散的知识点,怎么能够综合的串接起来是学习的一个很重要的目的,当然最好的方式就是用所学的知识点做一个项目了,所 ...
- linux系统编程综合练习-实现一个小型的shell程序(三)
上节中已经实现了对普通命令的解析,包括输入重定向,输出重定向,管道,后台作业,这次就来执行已经解析好的命令,对应的函数为:execute_command(),首先对带有管道的命令进行执行: 比如:&q ...
- linux系统编程综合练习-实现一个小型的shell程序(二)
上节minishell当中,已经初步实现了一个简单命令的解析,这节来继续对更加复杂命令进行解析,包含:输入重定向的解析.管道行的解析.输出重定向的解析以及是否有后台作业的解析,如下: 下面对其进行实现 ...
- Linux系统学习笔记之 1 一个简单的shell程序
不看笔记,长时间不用自己都忘了,还是得经常看看笔记啊. 一个简单的shell程序 shell结构 1.#!指定执行脚本的shell 2.#注释行 3.命令和控制结构 创建shell程序的步骤 第一步: ...
- Linux系统编程(33)—— socket编程之TCP程序的错误处理
上一篇的例子不仅功能简单,而且简单到几乎没有什么错误处理,我们知道,系统调用不能保证每次都成功,必须进行出错处理,这样一方面可以保证程序逻辑正常,另一方面可以迅速得到故障信息. 为使错误处理的代码不影 ...
- linux系统编程之进程(一)
今天起,开始学习linux系统编程中的另一个新的知识点----进程,在学习进程之前,有很多关于进程的概念需要了解,但是,概念是很枯燥的,也是让人很容易迷糊的,所以,先抛开这些抽象的概念,以实际编码来熟 ...
- linux系统编程之管道(三)
今天继续研究管道的内容,这次主要是研究一下命名管道,以及与之前学过的匿名管道的区别,话不多说,进入正题: 所以说,我们要知道命名管道的作用,可以进行毫无关系的两个进程间进行通讯,这是匿名管道所无法实现 ...
- linux系统编程之信号(七)
今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...
- Linux系统编程【2】——编写who命令
学到的知识点 通过实现who命令,学到了: 1.使用man命令寻找相关信息 2.基于文件编程 3.体会到c库函数与系统调用的不同 4.加深对缓冲技术的理解 who命令的作用 who命令的使用 在控制终 ...
随机推荐
- [LeetCode] 502. IPO 上市
Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Cap ...
- MAX10 ADC的一些基知识
MAX10 ADC 的一些知识 1. MAX 10 内部集成的12bit SAR ADC的特点为: a. 采样速率高达1Mhz. b. 模拟通道多达18个,单 ...
- 学习数据结构Day3
栈和队列 栈是一种线性结构,相比数组 他对应的操作是数组的子集 只能从一端进入,也只能从一端取出 这一端成为栈顶 栈是一种先进后出的数据结构,Last In First Out(LIFO) 程序调用的 ...
- java lambda怎么表达式判断被调用接口名称和接口中方法
1.首先能够用于lambda表达式的只能是interface,并且interface 中只有一个方法. 这就说明,只要找到接口类型就能确定用的是哪个方法.(如下:intTypeInterface.St ...
- pyhton数据类型:字典、集合、列表、元组
基本常识 元组 列表 字典 集合 初始化 tuple=(1,2,3,4) list=[1,2,3,4] dic={'a':12,'b':34} set={1,2,3,4} 元素索引 tuple[0] ...
- lambda表达式笔记
前几天一位好友分享了一篇文章,其中讲到了lambda表达式,正好最近看了一些内容,就做做笔记吧... lambda表达式服务于函数式接口,如果需要一个函数式接口的对象时,就可以用lambda表达式代替 ...
- Java开发笔记(一百三十二)Swing的表格
前面介绍了程序界面上一些简单控件的组合排列,它们用来表达相互之间联系较弱的信息倒还凑合,要是用来表达关联性较强的聚合信息就力不从心了.倘若只是简单信息的罗列,例如商品名称列表.新闻标题列表.学生姓名列 ...
- CSS3 @font-face 规则
指定名为"myFirstFont"的字体,并指定在哪里可以找到它的URL: @font-face { font-family: myFirstFont; src: url('San ...
- 微服务与SpringCloud简介
A.官网 https://spring.io/projects/spring-cloud B.简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用 ...
- 学习笔记之MongoDB
MongoDB - Wikipedia MongoDB is a cross-platform document-oriented database program. Classified as a ...