linux 22.3 终端,王晓博 2010.12.22-3-模拟linux shell 终端环境 执行所有shell命令

#define BUFFERSIZE 80

extern char *get_current_dir_name(void);

extern char *getenv(const char *name);

extern pid_t waitpid(pid_t pid, int *status, int options);

char buffer[BUFFERSIZE + 1];

int main()

{

char *path, *arg[10], *input;

int li_inputlen, is_bj, is_back, i, j, k, pid, status;

char lc_char;

while (1) {

/* initiations */

is_bj = 0;    /*redirection flag */

is_back = 0;    /*background */

/* shell prompt */

path = get_current_dir_name();

printf("[%s>wxb]$", path);

/*开始获取输入 */

li_inputlen = 0;

lc_char = getchar();

while (lc_char != '\n') {

if (li_inputlen < BUFFERSIZE)

buffer[li_inputlen++] = lc_char;

lc_char = getchar();

}

/*命令超长处理*/

if (li_inputlen >= BUFFERSIZE) {

printf("Your command is too long! Please re-enter your command!\n");

li_inputlen = 0;    /*reset */

continue;

} else

buffer[li_inputlen] = '\0';    /*加上串结束符号,形成字串 */

/*将命令从缓存拷贝到input中*/

input = (char *)malloc(sizeof(char) * (li_inputlen + 1));

strcpy(input, buffer);

/* 获取命令和参数并保存在arg中*/

for (i = 0, j = 0, k = 0; i <= li_inputlen; i++) {

/*管道和重定向单独处理 */

if (input[i] == '' || input[i] == '|') {

if (input[i] == '|')

pipel(input, li_inputlen);

else

redirect(input, li_inputlen);

is_bj = 1;

break;

}

/*处理空格、TAB和结束符。不用处理‘\n',大家如果仔细分析前面的获取输入的程序的话,

*不难发现回车符并没有写入buffer*/

if (input[i] == ' ' || input[i] == '\t' || input[i] == '\0') {

if (j == 0)    /*这个条件可以略去连在一起的多个空格或者tab */

continue;

else {

buffer[j++] = '\0';

arg[k] = (char *)malloc(sizeof(char) * j);

/*将指令或参数从缓存拷贝到arg中 */

strcpy(arg[k], buffer);

j = 0;    /*准备取下一个参数 */

k++;

}

} else {

/*如果字串最后是‘&',则置后台运行标记为1 */

if (input[i] == '&' && input[i + 1] == '\0') {

is_back = 1;

continue;

}

buffer[j++] = input[i];

}

}

free(input);    /*释放空间 */

/*如果输入的指令是quit则退出while,即退出程序*/

if (strcmp(arg[0], "quit") == 0) {

printf("bye-bye\n");

break;

}

/*如果输入的指令是about则显示作者信息,同时结束本条命令的解析过程 */

if (strcmp(arg[0], "about") == 0) {

printf("copyright by 1wangxiaobo@163.com\n");

continue;

}

if (is_bj == 0) {    /*非管道、重定向指令 */

/*在使用xxec执行命令的时候,最后的参数必须是NULL指针,

*所以将最后一个参数置成空值*/

arg[k] = (char *)0;

/*判断指令arg[0]是否存在 */

if (is_fileexist(arg[0]) == -1) {

printf("This command is not found?!\n");

for (i = 0; i < k; i++)

free(arg[i]);

continue;

}

/* fork a sub-process to run the execution file */

if ((pid = fork()) == 0)    /*子进程 */

execv(buffer, arg);

else /*父进程 */ if (is_back == 0)    /*并非后台执行指令 */

waitpid(pid, &status, 0);

/*释放申请的空间 */

for (i = 0; i < k; i++)

free(arg[i]);

}

}

return 0;

}

int is_fileexist(char *comm)

{

char *path, *p;

int i;

i = 0;

/*使用getenv函数来获取系统环境变量,用参数PATH表示获取路径*/

path = getenv("PATH");

p = path;

while (*p != '\0') {

/*路径列表使用‘:’来分隔路径 */

if (*p != ':')

buffer[i++] = *p;

else {

buffer[i++] = '/';

buffer[i] = '\0';

/*将指令和路径合成,形成pathname,并使用access函数来判断该文件是否存在*/

strcat(buffer, comm);

if (access(buffer, F_OK) == 0)    /*文件被找到 */

return 0;

else

/*继续寻找其它路径 */

i = 0;

}

p++;

}

/*搜索完所有路径,依然没有找到则返回-1*/

return -1;

}

int redirect(char *in, int len)

{

char *argv[30], *filename[2];

pid_t pid;

int i, j, k, fd_in, fd_out, is_in = -1, is_out = -1, num = 0;

int is_back = 0, status = 0;

/*这里是重定向的命令解析过程,其中filename用于存放重定向文件,

*is_in, is_out分别是输入重定向标记和输出重定向标记*/

for (i = 0, j = 0, k = 0; i <= len; i++) {

if (in[i] == ' ' || in[i] == '\t' || in[i] == '\0' || in[i] == '') {

if (in[i] == '>' || in[i] == '                /*重定向指令最多''各出现一次,因此num最大为2,

*否则认为命令输入错误*/

if (num < 3) {

num++;

if (in[i] == '                        is_in = num - 1;

else

is_out = num - 1;

/*处理命令和重定向符号相连的情况,比如ls>a */

if (j > 0 && num == 1) {

buffer[j++] = '\0';

argv[k] = (char *)malloc(sizeof(char) * j);

strcpy(argv[k], buffer);

k++;

j = 0;

}

} else {

printf("The format is error!\n");

return -1;

}

}

if (j == 0)

continue;

else {

buffer[j++] = '\0';

/*尚未遇到重定向符号,字符串是命令或参数 */

if (num == 0) {

argv[k] = (char *)malloc(sizeof(char) * j);

strcpy(argv[k], buffer);

k++;

}

/*是重定向后符号的字符串,是文件名 */

else {

filename[status] = (char *)malloc(sizeof(char) * j);

strcpy(filename[status++], buffer);

}

j = 0;    /*initate */

}

} else {

if (in[i] == '&' && in[i + 1] == '\0') {

is_back = 1;

continue;

}

buffer[j++] = in[i];

}

}

argv[k] = (char *)0;

if (is_fileexist(argv[0]) == -1) {

printf("This command is not founded!\n");

for (i = 0; i < k; i++)

free(argv[i]);

return 0;

}

if ((pid = fork()) == 0) {

/*存在输出重定向 */

if (is_out != -1)

if ((fd_out = open(filename[is_out], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) {

printf("Open out %s Error\n", filename[is_out]);

return -1;

}

/*存在输入重定向 */

if (is_in != -1)

if ((fd_in = open(filename[is_in], O_RDONLY, S_IRUSR | S_IWUSR)) == -1) {

printf("Open in %s Error\n", filename[is_out]);

return -1;

}

if (is_out != -1)

/*使用dup2函数将标准输出重定向到fd_out上,dup2(int oldfd,int newfd)实现的

*是把oldfd所指的文件描述符复制到newfd。若newfd为一已打开的文件描述词,

*则newfd所指的文件会先被关闭,dup2复制的文件描述词与原来的文件描述词

*共享各种文件状态*/

if (dup2(fd_out, STDOUT_FILENO) == -1) {

printf("Redirect Standard Out Error\n");

exit(1);

}

if (is_in != -1)

if (dup2(fd_in, STDIN_FILENO) == -1) {

printf("Redirect Standard Out Error\n");

exit(1);

}

execv(buffer, argv);

} else if (is_back == 0)    /*run on the TOP */

waitpid(pid, &status, 0);

for (i = 0; i < k; i++)

free(argv[i]);

if (is_in != -1) {

free(filename[is_in]);

close(fd_in);

}

if (is_out != -1) {

free(filename[is_out]);

close(fd_out);

}

return 0;

}

int pipel(char *input, int len)

{

char *argv[2][30];

int i, j, k, count, is_back = 0;

int li_comm = 0, fd[2], fpip[2];

char lc_char, lc_end[1];

pid_t child1, child2;

/*管道的命令解析过程*/

for (i = 0, j = 0, k = 0; i <= len; i++) {

if (input[i] == ' ' || input[i] == '\t' || input[i] == '\0' || input[i] == '|') {

if (input[i] == '|') {    /*管道符号 */

if (j > 0) {

buffer[j++] = '\0';

/*因为管道连接的是两个指令,所以用二维数组指针来存放命令和参数,

*li_comm是表示第几个指令*/

argv[li_comm][k] = (char *)malloc(sizeof(char) * j);

strcpy(argv[li_comm][k++], buffer);

}

argv[li_comm][k++] = (char *)0;

/*遇到管道符,第一个指令完毕,开始准备接受第二个指令 */

li_comm++;

count = k;

k = 0;

j = 0;

}

if (j == 0)

continue;

else {

buffer[j++] = '\0';

argv[li_comm][k] = (char *)malloc(sizeof(char) * j);

strcpy(argv[li_comm][k], buffer);

k++;

}

j = 0;    /*initate */

} else {

if (input[i] == '&' && input[i + 1] == '\0') {

is_back = 1;

continue;

}

buffer[j++] = input[i];

}

}

argv[li_comm][k++] = (char *)0;

if (is_fileexist(argv[0][0]) == -1) {

printf("This first command is not found!\n");

for (i = 0; i < count; i++)

free(argv[0][i]);

return 0;

}

/*指令解析结束*/

/*建立管道*/

if (pipe(fd) == -1) {

printf("open pipe error!\n");

return -1;

}

/*创建第一个子进程执行管道符前的指令,并将输出写到管道*/

if ((child1 = fork()) == 0) {

/*关闭读端*/

close(fd[0]);

if (fd[1] != STDOUT_FILENO) {

/*将标准输出重定向到管道的写入端,这样该子进程的输出就写入了管道 */

if (dup2(fd[1], STDOUT_FILENO) == -1) {

printf("Redirect Standard Out Error\n");

return -1;

}

/*关闭写入端 */

close(fd[1]);

}

execv(buffer, argv[0]);

} else {        /*父进程 */

/*先要等待写入管道的进程结束*/

waitpid(child1, &li_comm, 0);

/*然后我们必须写入一个结束标记,告诉读管道进程数据到这里就完了*/

lc_end[0] = 0x1a;

write(fd[1], lc_end, 1);

close(fd[1]);

if (is_fileexist(argv[1][0]) == -1) {

printf("This command is not founded!\n");

for (i = 0; i < k; i++)

free(argv[1][i]);

return 0;

}

/*创建第二个进程执行管道符后的指令,并从管道读输入流 */

if ((child2 = fork()) == 0) {

if (fd[0] != STDIN_FILENO) {

/*将标准输入重定向到管道读入端 */

if (dup2(fd[0], STDIN_FILENO) == -1) {

printf("Redirect Standard In Error!\n");

return -1;

}

close(fd[0]);

}

execv(buffer, argv[1]);

} else /*父进程 */ if (is_back == 0)

waitpid(child2, NULL, 0);

}

for (i = 0; i < count; i++)

free(argv[0][i]);

for (i = 0; i < k; i++)

free(argv[1][i]);

return 0;

}

/*-----------------------------------------------------------------------------注释: 模拟linux shell 终端环境  执行所有shell命令 ,命令区分空格等opensource 供爱好者修改学习执行过程如下:[root@192 ~]# ./shell[/root>wxb]$psPID TTY          TIME CMD5274 pts/1    00:00:00 bash5295 pts/1    00:00:00 shell5297 pts/1    00:00:00 ps[/root>wxb]$  psPID TTY          TIME CMD5274 pts/1    00:00:00 bash5295 pts/1    00:00:00 shell5298 pts/1    00:00:00 ps[/root>wxb]$lsanaconda-ks.cfg   install.log         shell           tmpanaconda-ks.cfg~  install.log.syslog  shell1.c~       Yozo_OfficeDesktop           k -l                shell.c         zImageeioXpacklog.txt   minicom.log         Source Insight  我的~[/root>wxb]$llThis command is not found?![/root>wxb]$  date2010年 12月 22日 星期三 17:35:44 CST[/root>wxb]$quitbye-bye[root@192 ~]#-----------------------------------------------------------------------------*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值