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命令的使用 在控制终 ...
随机推荐
- consul ACL 配置范例
service "dashboard" { policy = "write" } service "dashboard-sidecar-proxy&q ...
- Apollo环境配置
一.背景 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理 ...
- python json模块(15)
JSON 的全称是 JavaScript Object Notation,即 JavaScript 对象符号,它是一种轻量级.跨平台.跨语言的数据交换格式,其设计意图是把所有事情都用设计的字符串来表示 ...
- LeetCode 238. 除自身以外数组的乘积(Product of Array Except Self)
238. 除自身以外数组的乘积 238. Product of Array Except Self 题目描述 LeetCode LeetCode238. Product of Array Except ...
- [hdu 1062] Text Reverse | STL-stack
原题 题目大意: t组数据,每组为一行,遇到空格时讲前面的单词反转输出. 题解: 显然的栈题,遇到空格时将当前栈输出清空即可 #include<cstdio> #include<st ...
- 前端 html篇
web开发本质: html是一个标准,规定了大家怎么写网页 1.浏览器输入网址回车发生了什么事 1. 浏览器 给服务端 发送了一个消息2. 服务端拿到消息3. 服务端返回消息4. 浏览器展示页面 se ...
- Django连接多个数据库并实现读写分离
当一个项目当中有大量的数据的时候,你所有的IO操作都在一个数据库中操作,会造成项目的性能的降低.如果你能对项目中的数据进行读写分离的话,那么将大大提高你项目的性能.而Django自带的机制也对此提供了 ...
- 【LEETCODE】51、数组分类,简单级别,题目:581,830,1010,665
package y2019.Algorithm.array; /** * @ClassName FindUnsortedSubarray * @Description TODO 581. Shorte ...
- Keyboard Purchase CodeForces - 1238E (状压)
大意: 给定串$s$, 字符集为字母表前$m$个字符, 求一个$m$排列$pos$, 使得$\sum\limits_{i=2}^n|{pos}_{s_{i-1}}-{pos}_{s_{i}}|$最小. ...
- C语言开发中常用英文缩写
BIOS(Basic Input Output System): 基本输入输出系统 reference: https://baike.baidu.com/item/bios/91424?fr=alad ...