#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#define CMD_LINE 1024
#define PIPE_MAX 16
#define ARG_MAX 10
typedef struct {
char *arg[ARG_MAX];
char *in;
char *out;
} cmd_t;
extern int parse_token(char *buf, cmd_t cmd[]);
extern int parse(char *buf, cmd_t * cmd);
extern int test_parse(cmd_t cmd[], int len);
int main(int argc, char *argv[])
{
char buf[CMD_LINE];
cmd_t cmd[PIPE_MAX + 1];
int fd[PIPE_MAX][2];
int j, i;
int cmd_len, pipe_len;
pid_t pid;
while (1) {
printf("my_shell#"); //打印提示符
fgets(buf, CMD_LINE, stdin); //获得输入
buf[strlen(buf) - 1] = '\0'; //去掉结尾的换行符?
cmd_len = parse_token(buf, cmd);//解析命令
pipe_len = cmd_len - 1; //
if (pipe_len > PIPE_MAX)
continue;
for (i = 0; i < pipe_len; ++i)
pipe(fd[i]); //创建pipe_len个管道
for (i = 0; i < cmd_len; ++i) //创建cmd_len个进程
if ((pid = fork()) == 0) //判断是否为子进程
break; //如果是子进程,跳出for循环
if (pid == 0) { //循环中是子进程代码
if (pipe_len) {
if (i == 0) { //第一个子进程
close(fd[i][0]); //关闭管道的读取端
dup2(fd[i][1], 1); //复制管理的写入端为标准输出(标准输出会写入管道)
close(fd[i][1]); //关闭管道的写入端
for (j = 1; j < pipe_len; ++j)
close(fd[j][0]), //关闭无关进程的管道
close(fd[j][1]);
} else if (i == pipe_len) { //第pipe_len个子进程
close(fd[i - 1][1]); //关闭管道的写入端
dup2(fd[i - 1][0], 0); //复制管理的读取端为标准输出(标准输入会读取管道)
close(fd[i - 1][0]); //关闭管道的读取端
for (j = 0; j < pipe_len - 1; ++j)
close(fd[j][0]), //关闭无关进程的管道
close(fd[j][1]);
} else { //其他子进程
dup2(fd[i - 1][0], 0); //复制管理的读取端为标准输出(标准输入会读取管道)
close(fd[i][0]); //关闭管道的读取端
dup2(fd[i][1], 1); //复制管理的写入端为标准输出(标准输出会写入管道)
close(fd[i][1]); //关闭管道的写入端
for (j = 0; j < pipe_len; ++j) {
if ((j != i - 1) //关闭无关进程的管道
|| (j != i))
close(fd[j][0]),
close(fd[j]
[1]);
}
}
}
if (cmd[i].in) { //如果需要,打开输入文件并重定向
int fd = open(cmd[i].in, O_RDONLY);
dup2(fd, STDIN_FILENO);
close(fd);
}
if (cmd[i].out) { //如果需要,打开输出文件并重定向
int fd =
open(cmd[i].out,
O_RDWR | O_CREAT | O_TRUNC, 0644);
dup2(fd, STDOUT_FILENO);
close(fd);
}
execvp(cmd[i].arg[0], cmd[i].arg); //执行当前命令
fprintf(stderr, "Failed exec\n"); //执行命令失败后才会执行之后的代码
exit(127);
} //子进程代码结束
/* parent */
for (i = 0; i < pipe_len; ++i)
close(fd[i][0]), close(fd[i][1]);
for (i = 0; i < cmd_len; ++i)
wait(NULL); //等待子进程结束
}
return 0;
}
int parse_token(char *buf, cmd_t cmd[])
{
int n = 0;
#if 1
char *save_p;
char *p = strtok_r(buf, "|", &save_p);//以'|'分割命令将分割后的第一部分给p
while (p != NULL) {
parse(p, &cmd[n++]);
p = strtok_r(NULL, "|", &save_p);//将之后的部分给p,每次给一部分,每调用一次给下一部分
}
#else //下一块语句不被执行
cmd[n].arg[0] = "ls";
cmd[n].arg[1] = "-l";
cmd[n].arg[2] = NULL;
#endif
return n;
}
int test_parse(cmd_t cmd[], int len) //此函数未被调用
{
int i;
for (i = 0; i < len; ++i) {
printf("cmd[%d]:", i);
int j = 0;
while (cmd[i].arg[j])
printf(" %s", cmd[i].arg[j++]);
if (cmd[i].in)
printf("\tin:%s", cmd[i].in);
if (cmd[i].out)
printf("\tout:%s", cmd[i].out);
printf("\n");
}
return 0;
}
int parse(char *buf, cmd_t * cmd)
{
int i = 0;
cmd->in = NULL;
cmd->out = NULL;
char *p = strtok(buf, " ");//以空格分割命令(此时命令已被|分割过了)
while (p) {
if (*p == '<') { //如果命令以<开头,即需要做输入重定向
if (*(p + 1)) //这种情况是<后无空格直接跟文件名
cmd->in = p + 1;
else //这种情况是<后有空格
cmd->in = strtok(NULL, " ");
} else if (*p == '>') { //如果命令以>开头,即需要做输出重定向
if (*(p + 1)) //这种情况是>后无空格直接跟文件名
cmd->out = p + 1;
else //这种情况是>后有空格
cmd->out = strtok(NULL, " ");
} else
cmd->arg[i++] = p; //这种情况是正常命令或参数
p = strtok(NULL, " ");
}
cmd->arg[i] = NULL;
return 0;
}
温馨提示:内容为网友见解,仅供参考
如何用c语言写一个shell
\/\/shell指令参数个数int execute(char* arglist[])\/\/执行外部命令{ int error; error=execvp(arglist[0],arglist); if (error==-1) printf("failed\\n"); exit(1);}char* make(char *buf)\/\/将字符串传入参数表内{ char *cp; cp=malloc(strlen(buf)+1); if (...
怎么用C语言写一个DOSshell
伪代码:void main(void){ while (1) { cmd = get_cmd_from_input();switch (cmd) { case DIR:do_dir();break;case COPY:do_copy();break;} } } }
shell编程入门(shell编程入门简单吗)
图1是Linux系统层次结构图,Shell接收用户输入的命令,并把用户的命令从类似abed的ASCII码解释为类似0101的机器语言,然后把命令提交到系统内核处理;当内核处理完毕之后,把处理结果再通过Shell返回给用户。 换句话说: Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言...
如何编写一个shell脚本
echo "your login shell is not bash but $SHELL" fi 变量$SHELL包含了登录shell的名称,我们和\/bin\/bash进行了比较。 快捷操作符 熟悉C语言的朋友可能会很喜欢下面的表达式: [ -f "\/etc\/shadow" ] && echo "This computer uses shadow passwors" 这里&& 就是一个快捷操作符,如果左边的表达式为真则执行右...
如何在C语言中执行shell命令
if (execlp("ls", "ls", "-l", NULL) == -1) perror("Error Executing Command.\\n"); return 0; }在 shell 中运行这个 C 程序会输出 和你直接在 shell 中写 ls -l 的效果是一样的。然而,如果你使用不带 p 的 execl, 那么这样写就会报错。include <stdio.h>#include...
linux下如何用c语言调用shell命令
参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()...
用C语言实现shell中的 Pushd +n命令
\/\/ 就写一下思路吧 char* directorys[]; \/\/ 假定这个是栈 int main(char* args[]){ if (atoi(args[0]) < 0){ return false;} int index = atoi(arg[0]);\/\/ 从临时文件读取使用过的工作路径 directorys = readDirectorys();int len = directorys.length;\/\/ 取得需要设置的工作...
linux下怎样用c语言调用shell命令
方法一、system()的使用。我直接上代码吧 int system(const char *command);我在\/home\/book\/shell新建一个test.sh文件例如以下:#!bin\/bash echo $HOME echo "the is test!" test.c文件例如以下:#include<stdlib.h> int main(){ system("bash \/home\/book\/shell\/test.sh"); \/* chmod +...
简单shellcode学习
名为shellcode的变量位于.bss段,直接输入shellcode即可解决问题。前置知识:思路shellcode的编写 在编写前,先用c语言模拟流程,然后根据系统调用表编写汇编代码,确保参数正确传递。前置知识:文件描述符 文件描述符用于内核识别文件,打开文件后返回一个描述符,读写文件时也需要使用描述符。前置知识:exp...
如何在C语言中调用shell命令
1、system(执行shell 命令)相关函数 fork,execve,waitpid,popen 表头文件 #include<stdlib.h> 定义函数 int system(const char * string);函数说明 system()会调用fork()产生子进程,由子进程来调用\/bin\/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随 即返回原调用的进程。在...