大连网络宣传网站,湖北省建设厅官方网站八大员,免费开店平台,网站开发架构mvc一、知识补充
1.1 snprintf
snprintf() 是 C语言的一个标准库函数#xff0c;定义在stdio.h头文件中。 snprintf() 函数的功能是格式化字符串#xff0c;并将结果存储在指定的字符数组中。该函数的原型如下#xff1a;
int snprintf(char *str, size_t size, con…一、知识补充
1.1 snprintf
snprintf() 是 C语言的一个标准库函数定义在stdio.h头文件中。 snprintf() 函数的功能是格式化字符串并将结果存储在指定的字符数组中。该函数的原型如下
int snprintf(char *str, size_t size, const char *format[,argument...]);
参数
str指向一个字符数组用于存储格式化后的字符串该数组的大小至少为 size。size指定写入 str 数组中字符的最大个数包括最后的空字符 \0。format包含格式说明符的字符串它定义了后续参数的输出格式。[,argument...]可变参数列表与格式字符串中的格式说明符相匹配
return
如果参数 size 的值足够大则函数返回写入到 str 数组中的字符个数不包括结尾的空字符它的值位于[0, size-1]之间。如果出现编码错误则返回一个负数。请注意只有当这个返回值是非负且小于n时字符串才被完整地写入了。
1.2 fflush
fflush()函数更新缓存区。头文件#includestdio.h
调用fflush()会将缓冲区中的内容写到stream所指的文件中去.若stream为NULL则会将所有打开的文件进行数据更新。
int fflush(FILE *stream);
fflush(stdin)刷新缓冲区,将缓冲区内的数据清空并丢弃。 fflush(stdout)刷新缓冲区,将缓冲区内的数据输出到设备。 1 #includestdio.h2 #includeunistd.h3 int main()4 {5 printf(hello); 6 7 sleep(5);8 9 printf( world!\n);10 11 return 0;12 }
5秒后打印hello world 1 #includestdio.h2 #includeunistd.h3 int main()4 {5 printf(hello\n); 6 7 sleep(5);8 9 printf( world!\n);10 11 return 0;12 } 先打印hello5秒后打印 world\n有刷新功能 1 #includestdio.h2 #includeunistd.h3 int main()4 { 5 printf(hello);6 7 fflush(stdout);//将缓冲区的内容输出到设备中8 9 sleep(5);10 11 printf( world!\n);12 13 return 0;14 }先打印hello5秒后打印 world!
fflush()的作用是用来刷新缓冲区fflush(stdin)刷新标准输入缓冲区把输入缓冲区里的东西丢弃 fflush(stdout)刷新标准输出缓冲区把输出缓冲区里的东西强制打印到标准输出设备上。 1.3 fgets
fgets是C标准库中用于从文件或标准输入流中读取一行字符的函数常用于处理字符串输入。它的主要作用是读取文件或标准输入中的一行直到遇到换行符\n或达到指定的字符数为止。
char * fgets ( char * str, int num, FILE * stream );
参数
str这是一个指向字符数组的指针fgets将把读取的字符存储到这个数组中。num这是一个整数表示最多读取的字符数包括\0终止符。即使没有读取到换行符fgets也会在读取的字符数达到num-1时停止stream这是输入流可以是文件流如stdin、stdout或者其他文件指针。
返回值
如果读取成功fgets返回str即指向读取数据的字符数组。如果发生错误或达到文件末尾fgets返回NULL。
1.4 strtok
C语言字符函数和字符串函数-CSDN博客
可参考第11节中的strtok
1.5 getcwd getcwd是属于系统接口
#include unistd.h
char *getcwd(char *buf, size_t size);getcwd()会将当前工作目录的绝对路径复制到参数buf所指的内存空间中,参数size为buf的空间大小。
如果getcwd函数执行失败它将返回NULL。
#include stdio.h
#include stdlib.h
#include unistd.h
int main() {char cwd[1024];if (getcwd(cwd, sizeof(cwd))! NULL) {printf(当前工作目录是: %s\n, cwd);} else {perror(获取当前工作目录出错);return 1;}return 0;
}
像pwd就是调用getcwd这个系统接口
[zxwhcss-ecs-cc58 myshell]$ pwd
/home/zxw/linux/112/lesson16/myshell
1.6 chdir
chdir属于是系统接口
#include unistd.h
int chdir(const char *path//路径);用于改变当前工作目录其参数为Path 目标目录可以是绝对目录或相对目录。
成功返回0错误返回-1。
1.7 putenv
#include stdlib.h
int putenv(char *string);函数说明putenv()用来改变或增加环境变量的内容.
参数string 的格式为namevalue, 如果该环境变量原先存在, 则变量内容会依 value 改变, 否则此参数内容会成为新的环境变量。
返回值执行成功则返回0, 有错误发生则返回-1. 二、模拟Shell命令行解释器
#includeiostream
#includecstdio
#includecstdlib
#includecstring
#includestring
#includeunistd.h
#includesys/types.h
#includesys/wait.husing namespace std;const int basesize 1024;
const int argvnum 64;
const int envnum 64;
// 全局的命令行参数表
char *gargv[argvnum];
int gargc 0;using namespace std;
// 我系统的环境变量表
char *genv[envnum];// 全局的当前shell工作路径
char pwd[basesize];
char pwdenv[basesize];// 全局变量
int lastcode 0;string GetUserName()
{string name getenv(USER);return name.empty() ? None : name;
}string GetHostName()
{string hostname getenv(HOSTNAME);return hostname.empty() ? None : hostname;
}string GetPwd()
{string pwd getenv(PWD);return pwd.empty() ? None : pwd;// string pwd getenv(PWD);// 获取当前pwdif(nullptr getcwd(pwd,sizeof(pwd))) return None;// 修改环境变量snprintf(pwdenv,sizeof(pwdenv),PWD%s,pwd);putenv(pwdenv);return pwd;
}string LastDir()
{string curr GetPwd();if(curr / || curr None) return curr;size_t pos curr.rfind(/);if(pos string::npos) return curr;return curr.substr(pos1);
}// 1.命令行提示符
string MakeCommandLine()
{char command_line[basesize];snprintf(command_line,basesize,[%s%s %s]# ,GetUserName().c_str(),GetHostName().c_str(),GetPwd().c_str());GetUserName().c_str(),GetHostName().c_str(),LastDir().c_str());return command_line;
}void PrintCommandLine()
{printf(%s,MakeCommandLine().c_str());fflush(stdout);
}void debug()
{printf(argc:%d\n,gargc);for(int i 0; gargv[i]; i){printf(argv[%d]:%s\n,i,gargv[i]);}
}bool GetCommandLine(char command_buffer[],int size)// 2.获取用户命令
// 2.获取用户命令
bool GetCommandLine(char command_buffer[],int size)
{// 我们认为我们要将用户输入的命令行当成一个完整的字符串// ls -a -l -nchar *result fgets(command_buffer,size,stdin);if(!result){return false;}command_buffer[strlen(command_buffer)-1] 0;if(strlen(command_buffer) 0) return false;return true;
}//3.分析命令
void ParseCommandLine(char command_buffer[],int len)
{(void)len;memset(gargv, 0, sizeof(gargv));gargc 0;// ls -a -l -nconst char *sep ;gargv[gargc] strtok(command_buffer,sep);// 是刻意写的 ---》最后返回NULLwhile(gargv[gargc] strtok(nullptr,sep)); gargc--;
}void AddEnv(const char *item)
{int index 0;while(genv[index]){index;}genv[index] (char*)malloc(strlen(item)1);strncpy(genv[index],item,strlen(item)1);genv[index] nullptr;}// shell自己执行命令本质是shell调用自己的函数
bool CheckAndExecBuiltCommand()
{if(strcmp(gargv[0],cd) 0){// 内建命令没有创建子进程自己执行if(gargc 2){chdir(gargv[1]);lastcode 0;}else{lastcode 1;}return true;}else if(strcmp(gargv[0],export) 0){// export也是内建命令if(gargc 2){AddEnv(gargv[1]);lastcode 0;}else{lastcode 2;}return true;}else if(strcmp(gargv[0],env) 0){for(int i 0; genv[i]; i){printf(%s\n,genv[i]);}lastcode 0;return true;}else if(strcmp(gargv[0],echo) 0){if(gargc 2){// echo $?// echo helloif(gargv[1][0] $){if(gargv[1][1] ?){printf(%d\n,lastcode);lastcode 0;}}else{printf(%s\n,gargv[1]);}}else{lastcode 3;}return true;}return false;
}// 4.执行命令
// 在shell中
// 有些命令必须由子进程来执行
// 有些命令不能由子进程执行要由shell自己执行bool ExecuteCommand()
{// 让子进程进行执行pid_t id fork();if(id 0){return false;}if(id 0){//child//1.执行命令execvp(gargv[0],gargv);execvpe(gargv[0],gargv,genv);//2.退出exit(1);}int status 0;pid_t rid waitpid(id,status,0);if(rid 0)if(rid 0){//DO Nothingif(WIFEXITED(status)){lastcode WEXITSTATUS(status);}else{lastcode 100;}return true;}return false;
}// shell自己执行命令本质是shell调用自己的函数
bool CheckAndExecBuiltCommand()
// 作为一个shell获取环境变量应该从系统的配置
// 我们今天就直接从父进程获取环境变量
void InitEnv()
{if(strcmp(gargv[0],cd) 0)extern char **environ;int index 0;while(environ[index]){// 内建命令if(gargc 2){chdir(gargv[1]);}return true;genv[index] (char*)malloc(strlen(environ[index])1);strncpy(genv[index],environ[index],strlen(environ[index]1));index;}return false;genv[index] nullptr;
}int main()
{InitEnv();char command_buffer[basesize];while(true){PrintCommandLine();// 1.命令行提示符// command_line - outputif(!GetCommandLine(command_buffer, basesize))// 2.获取用户命令{continue;}// printf(%s\n,command_buffer); //ls -a -b --- ls -a -bParseCommandLine(command_buffer,strlen(command_buffer));// 3.分析命令//debug();//debug();//检查 if(CheckAndExecBuiltCommand()){continue;}ExecuteCommand(); // 4.执行命令}return 0;
}
通过模拟实现了解环境变量也是单独申请了一块地址的另外我们之前所学习的本地变量也是通过一个数组来维护的。也清楚的了解一些为什么要内建命令不能单独fork子进程。 文章转载自: http://www.morning.mkbc.cn.gov.cn.mkbc.cn http://www.morning.dschz.cn.gov.cn.dschz.cn http://www.morning.rfgc.cn.gov.cn.rfgc.cn http://www.morning.mkccd.cn.gov.cn.mkccd.cn http://www.morning.fjglf.cn.gov.cn.fjglf.cn http://www.morning.syssdz.cn.gov.cn.syssdz.cn http://www.morning.nrbqf.cn.gov.cn.nrbqf.cn http://www.morning.nnwmd.cn.gov.cn.nnwmd.cn http://www.morning.ggnjq.cn.gov.cn.ggnjq.cn http://www.morning.iuibhkd.cn.gov.cn.iuibhkd.cn http://www.morning.fhkr.cn.gov.cn.fhkr.cn http://www.morning.gbrps.cn.gov.cn.gbrps.cn http://www.morning.ktbjk.cn.gov.cn.ktbjk.cn http://www.morning.bgpb.cn.gov.cn.bgpb.cn http://www.morning.hlrtzcj.cn.gov.cn.hlrtzcj.cn http://www.morning.gfpyy.cn.gov.cn.gfpyy.cn http://www.morning.kwblwbl.cn.gov.cn.kwblwbl.cn http://www.morning.fwzjs.cn.gov.cn.fwzjs.cn http://www.morning.nwynx.cn.gov.cn.nwynx.cn http://www.morning.kqbzy.cn.gov.cn.kqbzy.cn http://www.morning.rzysq.cn.gov.cn.rzysq.cn http://www.morning.cpgdy.cn.gov.cn.cpgdy.cn http://www.morning.ypwlb.cn.gov.cn.ypwlb.cn http://www.morning.zlnyk.cn.gov.cn.zlnyk.cn http://www.morning.jrsgs.cn.gov.cn.jrsgs.cn http://www.morning.qsmdd.cn.gov.cn.qsmdd.cn http://www.morning.kqnwy.cn.gov.cn.kqnwy.cn http://www.morning.wypyl.cn.gov.cn.wypyl.cn http://www.morning.nlqmp.cn.gov.cn.nlqmp.cn http://www.morning.wfwqr.cn.gov.cn.wfwqr.cn http://www.morning.bfcxf.cn.gov.cn.bfcxf.cn http://www.morning.rgrys.cn.gov.cn.rgrys.cn http://www.morning.gxfpk.cn.gov.cn.gxfpk.cn http://www.morning.xnpj.cn.gov.cn.xnpj.cn http://www.morning.mpnff.cn.gov.cn.mpnff.cn http://www.morning.drhnj.cn.gov.cn.drhnj.cn http://www.morning.ayftwl.cn.gov.cn.ayftwl.cn http://www.morning.kdbcx.cn.gov.cn.kdbcx.cn http://www.morning.zmyhn.cn.gov.cn.zmyhn.cn http://www.morning.lfdrq.cn.gov.cn.lfdrq.cn http://www.morning.qkqhr.cn.gov.cn.qkqhr.cn http://www.morning.dcmnl.cn.gov.cn.dcmnl.cn http://www.morning.ygflz.cn.gov.cn.ygflz.cn http://www.morning.wspjn.cn.gov.cn.wspjn.cn http://www.morning.mnbcj.cn.gov.cn.mnbcj.cn http://www.morning.xqzrg.cn.gov.cn.xqzrg.cn http://www.morning.nzfqw.cn.gov.cn.nzfqw.cn http://www.morning.wbxtx.cn.gov.cn.wbxtx.cn http://www.morning.ctxt.cn.gov.cn.ctxt.cn http://www.morning.hxcuvg.cn.gov.cn.hxcuvg.cn http://www.morning.ckrnq.cn.gov.cn.ckrnq.cn http://www.morning.zlmbc.cn.gov.cn.zlmbc.cn http://www.morning.kaakyy.com.gov.cn.kaakyy.com http://www.morning.tbnpn.cn.gov.cn.tbnpn.cn http://www.morning.rqsr.cn.gov.cn.rqsr.cn http://www.morning.mwpcp.cn.gov.cn.mwpcp.cn http://www.morning.plfrk.cn.gov.cn.plfrk.cn http://www.morning.rxdsq.cn.gov.cn.rxdsq.cn http://www.morning.wsnbg.cn.gov.cn.wsnbg.cn http://www.morning.xylxm.cn.gov.cn.xylxm.cn http://www.morning.rglp.cn.gov.cn.rglp.cn http://www.morning.cniedu.com.gov.cn.cniedu.com http://www.morning.mttqp.cn.gov.cn.mttqp.cn http://www.morning.rwcw.cn.gov.cn.rwcw.cn http://www.morning.mtrrf.cn.gov.cn.mtrrf.cn http://www.morning.dmrjx.cn.gov.cn.dmrjx.cn http://www.morning.krbjb.cn.gov.cn.krbjb.cn http://www.morning.ryznd.cn.gov.cn.ryznd.cn http://www.morning.nfzzf.cn.gov.cn.nfzzf.cn http://www.morning.hdtcj.cn.gov.cn.hdtcj.cn http://www.morning.khlxd.cn.gov.cn.khlxd.cn http://www.morning.pzbqm.cn.gov.cn.pzbqm.cn http://www.morning.hfytgp.cn.gov.cn.hfytgp.cn http://www.morning.stsnf.cn.gov.cn.stsnf.cn http://www.morning.hrhwn.cn.gov.cn.hrhwn.cn http://www.morning.jghty.cn.gov.cn.jghty.cn http://www.morning.sgnjg.cn.gov.cn.sgnjg.cn http://www.morning.dfbeer.com.gov.cn.dfbeer.com http://www.morning.nggbf.cn.gov.cn.nggbf.cn http://www.morning.xpfwr.cn.gov.cn.xpfwr.cn