龙空技术网

linux下的C开发14,花三分钟,编写C语言程序模拟shell执行命令

IT刘小虎 1104

前言:

如今小伙伴们对“c语言shell程序”大概比较关切,大家都需要学习一些“c语言shell程序”的相关文章。那么小编同时在网摘上搜集了一些对于“c语言shell程序””的相关文章,希望兄弟们能喜欢,各位老铁们一起来学习一下吧!

上一节介绍了 linux 中的文件类型,并在文章最后使用 C语言编写了程序,该程序能够接受一个文件名参数,并打印出该文件的类型。不知道大家如何,反正我当初学编程时,发现(编译后的)可执行程序居然也能像(编写代码阶段的)函数一样接收参数,觉得太神奇了。

小编刚学习 C语言时,是在 windows 中学习的,编译出的程序都是双击执行,从来没想过编译后的可执行程序还能接收参数。可执行程序怎样接收参数的呢?

事实上,不仅仅是上一节的C语言程序能够接受参数,linux 中的大部分 shell 命令都是可以接收参数的,例如 ls 命令可以接收 -l 参数,输出更加详细的文件信息:

# ls -ltotal 24-rwxr-xr-x 1 root root 13205 Dec 22 18:26 a.out-rw-r--r-- 1 root root 427 Dec 21 21:01 main.c-rw-r--r-- 1 root root 1653 Dec 22 18:26 test.c

执行删除命令 rm 也需要指定文件名:

# rm a.out

ls 和 rm 本质上也是 linux 中的可执行程序,linux 中的大部分程序都是由 C语言编写的。C语言程序总是有个入口函数(常常是 main 函数),入口函数的原型如下:

int main(int argc, char* argv[]);

其中 argc 是命令参数的数目,argv 则是指向参数的各个指针构成的数组。在 shell 中输入命令(其实就是可执行程序)后,shell 会调用 exec 函数族执行该命令。输入 man 命令查询 exec 函数族的手册:

容易看出,exec 函数族在创建新进程执行命令时,允许传入若干参数给命令。

这就明白了,shell 也是一个进程,它会记录用户输入的命令和命令参数,在调用 exec 函数族执行命令时,把记录的参数传递给命令。C语言模拟 shell 传递参数给可执行程序

知道了 linux 中可执行程序接收参数的原理后,编写程序模拟 shell 传递参数就不难了。我们先编写一个能够接受参数的C语言程序:

#include <stdio.h>int main(int argc, char* argv[]){ int i = 0; printf("\n"); for(i=0; i<argc; i++) printf("\t%s\n", argv[i]); printf("\n"); return 0;}

程序很简单,就是将接收到的参数打印出来。编译并执行之,得到如下结果:

# gcc t.c# ./a.out  ./a.out# ./a.out hello embedTime ./a.out hello embedTime#
因为规定所有有效参数之后 argv 指向 NULL,所以遍历 C语言程序接收到的所有参数时,上面的 for 循环也可以写成:for(i=0; NULL!=argv[i]; i++)。

现在再编写一个程序,在这个程序中,我们将使用 exec 函数族模拟 shell 执行由 t.c 编译而来的可执行程序 a.out,并向其传送指定的参数。

#include <stdio.h>#include <unistd.h>#include <string.h>#include <errno.h>int main(){ char* filename = "./a.out"; printf("now run %s\n", filename); char *argv[] = {"hello","embedTime",NULL}; int ret = execvp(filename, argv);  if(ret<0) printf("ret: %d %s\n", ret, strerror( errno )); printf("sim shell exit.\n\n"); return 0;}

代码很简单,将“hello”和“embedTime”两个参数填入 argv 里,再调用 execvp 函数模拟 shell 执行 a.out 程序,编译执行:

模拟 shell 的 sim.out 程序的确成功把上面两个参数传递给 a.out 了,但是 sim.out 程序最后的 “sim shell exit.”信息却没有输出。这是因为 sim.out 进程被 a.out 进程替代了。

编写完美模拟 shell 的C语言程序

这样模拟 shell 并不完美,总不至于为了执行一个进程,shell 都得退出吧?还记得第 11 节介绍的多进程 C语言程序编写方法吗?为了完美模拟 shell,可以 fork 出一个子进程,在子进程中执行 a.out ,请看如下代码:

#include <stdio.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/wait.h>#include <errno.h>int main(){ char* filename = "./a.out"; pid_t pid = fork(); if(0==pid){ printf("now run %s\n", filename); char *argv[] = {"hello","embedTime",NULL}; int ret = execvp(filename, argv);  if(ret<0) printf("ret: %d %s\n", ret, strerror( errno )); }else{ printf("\nsim shell running...\n"); int status; wait(&status); printf("sim shell exit.\n\n"); } return 0;}

现在再编译执行,发现我们不仅成功模拟了 shell 执行 a.out ,而且 a.out 执行时,sim.out 也没有被替换,终于较为完美的模拟了 shell 传递参数给可执行程序。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

标签: #c语言shell程序