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命令的使用 在控制终 ...
随机推荐
- Java之第一个Java程序
编写第一个Java程序 打开文本编辑器,输入以下代码 public class Hello { public static void main(String[] args) { System.out. ...
- mongoDB主从和集群
主从(windows下的配置) 主服务器设置 mongod --dbpath=F:\mongoDB\db --master \\dbpath是设定数据存放路径 --master是指定为主库 从服务器设 ...
- Linux 上安装 appium
在linux 环境下安装需要以下几步:1.安装node.js, 通过 uname -a 命令查看到我的Linux系统位数是64位(备注:x86_64表示64位系统, i686 i386表示32位系 ...
- python is 和 == 区别(8)
在python中is和==都说常用的运算符之一,主要用于检测两个变量是否相等,返回True或者False,具体区别在哪呢? 一.前言 在讲解is和==区别直接先讲解一下内置函数id(),其实在文章 p ...
- 了解一下JVM和GC工作机制
题外话:很久没有写博客了,事情颇多,今天空闲下来,学习一下顺便写一下自己的了解,机会总是留给有准备的人,所以平常一定要注意知识的巩固和积累.知识的深度也要有一定的理解,不比别人知道的多,公司干嘛选你? ...
- java File源码理解,探索File路径
1.方法: new File(path); 我们知道根据输入的路径path的不同 ,File可以根据path的不同格式,来访问文件.那么,path的形式有几种呢? 根据源码 可以知道,输入的路径pat ...
- 喜马拉雅 FM 已购付费音频下载
如何下载在喜马拉雅 FM 中已购买的付费音频.之前想分享自己购买的付费音频给朋友听,碍于喜马拉雅 FM 的音频不能直接导出,所以准备自己搞个下载的小软件. 仅可下载已购买的付费音频.当然,如果你是会员 ...
- [转帖]ARM A77+G77最强公版架构:联发科5G SoC计划11月26日发布
ARM A77+G77最强公版架构:联发科5G SoC计划11月26日发布 https://www.cnbeta.com/articles/tech/909025.htm 主流的手机SoC厂商已经纷纷 ...
- int main(int argc, char *argv[])解释
int main(int argc, char *argv[]) 详解: #include <stdio.h> int main(int argc, char *argv[]) { int ...
- 【LEETCODE】48、数组分类,简单级别,题目:189,217,219,268,283,414
package y2019.Algorithm.array; import java.util.Arrays; import java.util.Stack; /** * @ClassName Rot ...