当前位置: 首页 > news >正文

南昌专门做网站遵义市城乡建设局安管人员考试网站

南昌专门做网站,遵义市城乡建设局安管人员考试网站,WordPress添加作者信息小工具,申请一个域名文章目录 一、打印命令行提示符二、读取键盘输入的指令三、指令切割四、普通命令的执行五、内建指令执行5.1 cd指令5.2 export指令5.3 echo指令 六、结语 一、打印命令行提示符 const char* getusername() // 获取用户名 {return getenv(USER); }const char* geth… 文章目录 一、打印命令行提示符二、读取键盘输入的指令三、指令切割四、普通命令的执行五、内建指令执行5.1 cd指令5.2 export指令5.3 echo指令 六、结语 一、打印命令行提示符 const char* getusername() // 获取用户名 {return getenv(USER); }const char* gethostname() // 获取主机名 {return getenv(HOSTNAME); }const char* getpwd() // 获取当前所处的目录 {char* pos strrchr(getenv(PWD), /); // 查找最后一个 ‘/’ if(*(pos1) ! \0) return pos1; // 说明不是根目录返回最后一个文件夹return pos; }void tooltip() // 打印命令行提示框 {printf(LEFT %s%s %s RIGHT PROMPT , getusername(), gethostname(), getpwd()); }代码分析获取基础信息本质上是通过调用 getenv 接口来获取对应环境变量的值。借助 strrchr 函数来查找当前路径中的最后一个文件分隔符 /它有可能是文件分隔符也有可能是根目录因此要单独判断。 二、读取键盘输入的指令 char command[1024]; // 存储键盘输入的指令int getcommand(char* command, int size) // 读取指令 {memset(command, \0, size);char* ret fgets(command, size, stdin); // 这里 ret 一定不为空因为至少会输入一个回车fgets 可以读取回车assert(ret ! NULL);(void)ret;// “假装使用一下ret防止有些编译器警告”// aaabc\n\0command[strlen(command)-1] \0; // 去掉结尾的 \nreturn 1; }int interact(char* command, int size) // 交互 {tooltip();while(getcommand(command, size) (strlen(command) 0)){tooltip();} }int main() {interact(command, sizeof(command)); // 交互printf(echo: %s\n, command);return 0; }代码分析键盘输入的指令本质上就是一串字符串这里不能用 scanf 来获取字符串因为 scanf 是不会读取空格和回车的遇到空格和回车就停止读取而我们一般的指令都是带选项的指令和选项之间一般会用空格隔开用 scanf 会导致我们指令读不全。这里使用 fgets 函数来读取键盘输入其第一参数是存储指令的空间的首地址第二个参数是空间的大小第三个参数是从哪个文件流中读取一个 C/C 程序默认会打开三个文件流 stdin、stdout、stderr这里选择从 stdin 中读取也就是从标准输入中读取。gets 函数会在结尾自动帮我们添加 \0并且当读取的字符个数大于存储容量时该函数会自动在结尾放 \0因此我们可以不用考虑为 \0 预留空间或者认为的在字符串结尾加 \0。其次该函数读取成功返回 command 的首地址否则返回 NULL在当前场景下除非读取错误否则至少都会读入一个 \n一般我们输入完指令就是敲回车什么指令不输也敲回车因此正常情况下 ret 不可能为 NULL。这里还要考虑删除掉读取到的 \n因为我们不需要它我们只要完整的指令。 三、指令切割 #define SEPARATOR // 指令分隔符 char* argv[ARGC_LONG] {NULL}; // 存储指令和选项的起始地址void commandcut(char* command, char** argv, int argvsize) // 指令切割 {memset(argv, 0, argvsize); // 清空char cop_command[COMMAND_LONG] {\0}; // 保证 command 串不被改变for(int i 0; command[i] ! \0; i){cop_command[i] command[i];}// 开始切割子串char* ret strtok(cop_command, SEPARATOR);int i 0;while(ret ! NULL){argv[i] ret;ret strtok(NULL, );} }int main() {while(1){// 1、交互获取命令行参数interact(command, sizeof(command)); // 交互// 到这里说明指令已经获取到了接下来将指令打散// 2、指令切割commandcut(command, argv, sizeof(argv));for(int i 0; argv[i]; i){printf([%d]: %s\n, i, argv[i]);}printf(echo: %s\n, command);}return 0; }代码分析这一步主要是借助 strtok 函数将获取到的指令切割成一个一个的子串将所有子串的起始地址存储在 argv 里面。注意 strtok 函数会改变原空间的内容因此创建了一段临时的空间 cop_command。 四、普通命令的执行 void normalcommandexecution(char** _argv, int* _lastcode) // 普通命令的执行 {pid_t id fork();if(id 0){perror(fork);}else if(id 0){// childint ret execvp(_argv[0], _argv);if(ret -1){perror(exeecp);exit(EXIT_CODE);}}else{// fatherint status;pid_t ret waitpid(id, status, 0); // 阻塞等待if(ret id){*_lastcode WEXITSTATUS(status);}} }int main() {while(1){// 1、交互获取命令行参数interact(command, sizeof(command)); // 交互// 到这里说明指令已经获取到了接下来将指令打散// 2、指令切割commandcut(command, argv, sizeof(argv));// 3、普通命令执行normalcommandexecution(argv, lastcode);}return 0; }代码分析对于 ls 这种普通指令非内建指令先通过 fork 创建子进程然后再调用 execvp 接口进行程序替换去执行输入的指令。 五、内建指令执行 5.1 cd指令 bool isnormalcommand(char **_argv) // 指令判断 {if (strcmp(_argv[0], cd) 0)return false;return true; }void changpwd(char** _argv) // 更改当前工作目录 {chdir(_argv[1]); // 更改当前工作目录// getpwd(pwd, sizeof(pwd));sprintf(getenv(PWD), %s, getcwd(pwd, sizeof(pwd))); // 修改环境变量 }void builtincommand(char **_argv) // 内建命令执行 {if (strcmp(_argv[0], cd) 0){changpwd(_argv);} }int main() {while (1){// 1、交互获取命令行参数interact(command, sizeof(command)); // 交互// 到这里说明指令已经获取到了接下来将指令打散// 2、指令切割commandcut(command, argv, sizeof(argv));// 3、指令判断// 3、普通命令执行if (isnormalcommand(argv)) // 普通指令normalcommandexecution(argv, lastcode);else // 内建指令builtincommand(argv);}return 0; }代码分析要考虑内建指令那在指令切割之后要先对指令进行判断。内建指令不需要创建子进程去执行而是直接由当前的 bash 进程去执行。比如说 cd 指令执行完 cd 指令后我们要让当前的 bash 更改工作目录而不是让其创建子进程去执行 cd 指令那样改变的就是子进程的工作目录。可以发现一个指令执行完后如果会对 bash 产生影响那么它就必须是内建指令。其次关于 cd 指令它改变了当前的工作目录这一点该如何理解呢我 myshell 就是一个可执行程序我的源代码和编译得到的可执行文件始终都放在 /home/wcy/linux-s/2023-10-28a/myshell 目录下你 cd 命令凭什么能改变我的工作目录其实并不然这里改变工作目录是一个可执行程序在变成进程产生 PCB 对象后PCB 里面维护了一个属性就叫做当前可执行程序的工作目录cd 指令改变的其实就是这一属性并不是改变 myshell 程序的存储位置我们通过调用 chdir 系统调用来修改这一属性。最后因为我们前面是通过环境变量来获取当前工作目录而环境变量在被当前 myshell 进程从父进程继承下来后是不会自动发生改变的因此在执行完 cd 指令后我们要对 PWD 环境变量进行修改环境变量本质上就是存储在内存中的一段字符串信息因此我们可以采用 sprintf 函数对该字符串信息进行修改。 5.2 export指令 #define USER_ENV_SIZE 100 // 允许用户添加的环境变量个数 #define USER_ENV_LONG 1024 // 用户一个环境变量的最大长度char userenv[USER_ENV_SIZE][USER_ENV_LONG]; // 保存用户添加的环境变量 int userenvnum 0; // 当前用户输入的环境变量个数void exportcommand(char** _argv, char(*_userenv)[USER_ENV_LONG], int* _userenvnum) {// 将用户输入的环境变量存储起来strcpy(_userenv[*_userenvnum], _argv[1]);int ret putenv(_userenv[(*_userenvnum)]);if (ret 0)perror(putenv); }代码分析只要 bash 不退出我们每次添加的环境变量都应该被保存起来我们输入的环境变量是被当做指令保存在 command 里面当下一次输入指令上一次输入的内容就会被清空。putenv 添加环境变量并不是把对应的字符串拷贝到系统的表当中而是把该字符串的地址保存在系统的表中因此我们要确保保存环境变量字符串的那个地址里的环境变量不会被修改所以我们需要为用户输入的环境变量也就是那一串字符串单独开辟一块空间进行存储保证在内次重新输入指令的时候不会影响到之前用户添加的环境变量。因为环境变量本质就是一个字符串所以这里我们定义了一个字符二维数组来存储用户输入的环境变量先把用户输入的环境变量存入我们定义的这个数组然后再调用 putenv 函数将数组中的内容添加到当前的环境变量。这样就可以保证只要当前 bash 不退出用户历史上添加的环境变量都在。这里涉及到二维数组传参的问题再来回顾一下数组名表示首元素地址二维数组的首元素是一个一维数组所以函数形参的类型是一个字符一维数组的地址也就是 char(*)[USER_ENV_LONG]。 5.3 echo指令 void echocommand(char **_argv, int _argc) {if (_argv[1][0] $){char *ptr _argv[1] 1;printf(%s\n, getenv(ptr));}else{int i 1;while (i _argc){char *ret strtok(_argv[i], \);while (ret ! NULL){printf(%s, ret);ret strtok(NULL, \);}printf(%c, );i;}printf(\n);} }代码分析echo 指令需要考虑将输入的 去掉其次可能连续输入多个字符串还要考虑 echo 和 $ 配合使用是去打印环境变量的值。 小结当我们登陆的时候系统就是要启动一个 shell 进程我们 shell 本身的环境变量是在用户登录的时候shell 会读取用户目录下的 .bash_profile 文件里面保存了导入环境变量的方式。 六、结语 今天的分享到这里就结束啦如果觉得文章还不错的话可以三连支持一下春人的主页还有很多有趣的文章欢迎小伙伴们前去点评您的支持就是春人前进的动力
http://www.hkea.cn/news/14585505/

相关文章:

  • 四大门户网站流量对比二手房地产中介网站建设
  • 网站空间要备案吗微网站模板制作
  • 做电影网站什么系统好vr全景网站怎么做
  • 电子商务网站的重要性现代农业建设 乡网站
  • 婚恋网站排名wordpress消息系统
  • 手机建站北京网络推广平台
  • 布吉网站建设哪家服务周到设计软件培训
  • 自己做的网站能备案吗商标查询入口
  • 设计官网大全南阳seo网站排名优化
  • 淘宝建设网站的好处建设网站企业银行
  • 做抢单软件的网站asp.net jsp 网站
  • phpcms 网站栏目枣阳网站建设吧
  • 哪些网站可以看一级a做爰片一个服务器下怎么做两个网站吗
  • 购物网站建设规划书东营建设信息网招聘
  • 外贸公司的网站建设模板深圳微信网站建设
  • 济宁住房与建设网站杭州外贸网站建设
  • php网站里放asp专业网站设计网络服务
  • 网站很卡如何优化wordpress共享到微信
  • 有什么交易网站源码wordpress主题 手机app
  • 深圳营销型网站定制合肥app建设公司
  • 网站建设中页面设计国内开源代码网站
  • 一起装修网官方网站哈尔滨建设工程招投标网
  • 网站改版设计要多久做外贸网站用哪些小语种
  • 找别人网站开发没给我源代码开发一个区块链app多少钱
  • 软件开发培训计划唐山网站建设优化
  • 官网建站系统个人永久免费自助建站
  • wordpress 切换主题长沙优化网站多少钱
  • 一级域名的网站制作网站报错403
  • 学校网站建设步骤过程wordpress怎么进登录
  • 漫画做视频在线观看网站新手搭建网站教程视频