一个月,学了很多东西,遇到很多问题,觉得自己很白菜,总归每天在进步,总结下
大概做了三件事:
- 设计实现商城道具管理系统,数据库(mysql)+后端(python,flask)+前端(js,html,css)
- 实现一个脚本解释器,c语言编程
- 实现一个运维脚本,shell编程
操作系统debian,连接远程服务器开发putty
- 商城道具管理系统
_mini.py (control层)
_view.py (view层)
_dao.py (model层)
_template (html)
_static (图片,js,css)
- 脚本解释器
类似bash
#define TRUE 1 #define max_name 256 #define max_path 1024 #define max_prompt 1024 #define MAXLINE 4096 #define MAXARG 20 #define MAXPIDTABLE 1024 #define BACKGROUND 1 #define IN_REDIRECT 2 #define OUT_REDIRECT 4 #define OUT_REDIRECT_APPEND 8 #define IS_PIPED 16 #define MAX_TYPE_PROMPT 20 #ifdef READLINE_ON #include <readline/readline.h> #include <readline/history.h> #endif #include <unistd.h> #include <pwd.h> #include <signal.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> struct parse_info { int flag; char* in_file; char* out_file; char* command2; char** parameters2; }; char *buffer; pid_t BPTable[MAXPIDTABLE]; struct passwd *pwd; //显示个性化的命令行提示符 void display(char *prompt){ pwd=getpwuid(getuid());//get recent uid char hostname[max_name]; char pathname[max_path]; int len; getcwd(pathname,max_path);//get recent pathname if(gethostname(hostname,max_name)==0)//get hostname sprintf(prompt,"[qjjshell]%s@%s:",pwd->pw_name,hostname); else sprintf(prompt,"[qjjshell]%s@unknown:",pwd->pw_name); len = strlen(prompt); if(strlen(pathname) < strlen(pwd->pw_dir) || strncmp(pathname,pwd->pw_dir,strlen(pwd->pw_dir))!=0)//get pathname sprintf(prompt+len,"%s",pathname); else sprintf(prompt+len,"~%s",pathname+strlen(pwd->pw_dir)); len = strlen(prompt); if(geteuid()==0)//get premission sprintf(prompt+len,"#"); else sprintf(prompt+len,"$"); return; } //读取命令行输入的命令 int readcmd(char **command,char **parameters,char *prompt){ #ifdef READLINE_ON free(buffer); buffer = readline(prompt); if(feof(stdin)) { printf("\n"); exit(0); } #else printf("%s",prompt); char* Res_fgets = fgets(buffer,MAXLINE,stdin); if(Res_fgets == NULL) { printf("\n"); exit(0); } #endif if(buffer[0] == '\0') return -1; char *pStart,*pEnd; int count = 0; int isFinished = 0; pStart = pEnd = buffer; while(isFinished == 0) { while((*pEnd == ' ' && *pStart == ' ') || (*pEnd == '\t' && *pStart == '\t'))//ok { pStart++; pEnd++; } if(*pEnd == '\0' || *pEnd == '\n')//exit when reading is not end but has not cmd { if(count == 0) return -1; break; } while(*pEnd != ' ' && *pEnd != '\0' && *pEnd != '\n')//plus pEnd pEnd++; if(count == 0)//reading command=paramaters[0],count=2 { *command = pStart; parameters[0]=pStart; count += 2; } else if(count <= MAXARG)//reading parameters,parameter[1]=***,count=3,parameter[2]=***,count=4 { parameters[count-1] = pStart; count++; } else { break; } if(*pEnd == '\0' || *pEnd == '\n') { *pEnd = '\0'; isFinished = 1; } else { *pEnd = '\0'; pEnd++; pStart = pEnd; } } parameters[count-1] = NULL;//parameter[3]=NULL,count=4 return count; } //内部命令的解析执行 int builtin_cmd(char *command, char **parameters){ pwd=getpwuid(getuid());//get recent uid if(strcmp(command,"exit")==0 || strcmp(command,"quit")==0) exit(0); else if(strcmp(command,"cd")==0) { char *cd_path = NULL; if(parameters[1] == NULL)//make "cd" as "cd .." { parameters[1] = malloc(3 * sizeof(char)); parameters[1][0]= '.'; parameters[1][1]= '.'; parameters[1][2]= '\0'; } if(parameters[1][0] == '~') { cd_path = malloc(strlen(pwd->pw_dir)+strlen(parameters[1])); if(cd_path == NULL) { printf("cd:malloc failed.\n"); } strcpy(cd_path,pwd->pw_dir); strncpy(cd_path+strlen(pwd->pw_dir),parameters[1]+1,strlen(parameters[1])); } else { cd_path = malloc(strlen(parameters[1]+1)); if(cd_path == NULL) { printf("cd:malloc failed.\n"); } strcpy(cd_path,parameters[1]); } if(chdir(cd_path)!= 0) printf("-wshell: cd: %s:%s\n",cd_path,strerror(errno)); free(cd_path); } else if(strcmp(command,"type")==0) { char *typeprompt; if((strcmp(parameters[1],"cd")==0) ||(strcmp(parameters[1],"exit")==0) || (strcmp(parameters[1],"type")==0)) { typeprompt="shell内嵌";printf("%s 是 %s\n",parameters[1],typeprompt); } else if((strcmp(parameters[1],"if")==0) ||(strcmp(parameters[1],"else")==0) || (strcmp(parameters[1],"while")==0)) { typeprompt="qjjshell关键字";printf("%s 是 %s\n",parameters[1],typeprompt); } else if(strcmp(parameters[1],"ls")==0) { typeprompt="别名";printf("%s 是 %s\n",parameters[1],typeprompt); } else{ return 1; } } return 0; } //进程信号处理 void sig_handler(int sig)//background process print child process pid when child process exited { pid_t pid; int i; for(i=0;i<MAXPIDTABLE;i++) if(BPTable[i] != 0) //only handler the background processes { pid = waitpid(BPTable[i],NULL,WNOHANG); if(pid > 0) { printf("process %d exited.\n",pid); BPTable[i] = 0; //clear } else if(pid < 0) { if(errno != ECHILD) perror("waitpid error"); } } return; } //结构体的初始化 int parse_info_init(struct parse_info *info) { info->flag = 0; info->in_file = NULL; info->out_file = NULL; info->command2 = NULL; info->parameters2 = NULL; return 0; } //命令的解析 int parsing(char **parameters,int ParaNum,struct parse_info *info)//"ls -l -a",3,struct, { int i; parse_info_init(info); if(strcmp(parameters[ParaNum-1],"&") ==0)//judge wether backgroud process { info->flag |= BACKGROUND; parameters[ParaNum-1] = NULL; ParaNum--; } for(i=0;i<ParaNum;) { if(strcmp(parameters[i],"<<")==0 || strcmp(parameters[i],"<")==0)//input redirect,"cat < in.c" { info->flag |= IN_REDIRECT; info->in_file = parameters[i+1];//parameter[2] parameters[i] = NULL;//parameter[1] i+=2;//i=3 } else if(strcmp(parameters[i],">")==0)//output redirect,"echo 'hello' > out.c" { info->flag |= OUT_REDIRECT; info->out_file = parameters[i+1];//parameter[3] parameters[i] = NULL;//parameter[2] i+=2;//i=4 } else if(strcmp(parameters[i],">>")==0) { info->flag |= OUT_REDIRECT_APPEND; info->out_file = parameters[i+1]; parameters[i] = NULL; i+=2; } else if(strcmp(parameters[i],"|")==0) { info->flag |= IS_PIPED; parameters[i] = NULL; info->command2 = parameters[i+1]; info->parameters2= ¶meters[i+1]; break; } else i++; } return 1; } void main(){ int status,i; pid_t pid; char *command = NULL; char **parameters; char prompt[max_prompt]; int ParaNum; struct parse_info info; pid_t ChdPid,ChdPid2; for(i=0;i<MAXPIDTABLE;i++)//进程组标志位的初始化 BPTable[i] = 0; parameters = malloc(sizeof(char *)*(MAXARG+2)); buffer = malloc(sizeof(char) * MAXLINE); if(parameters == NULL || buffer == NULL)//错误检测 { printf("bashshell error:malloc failed.\n"); return; } if(signal(SIGCHLD,sig_handler) == SIG_ERR)//进程结束或者意外停止的时候SIGCHLD会被发送给父进程 perror("signal() error"); while(TRUE){ //一直运行 int pipe_fd[2],in_fd,out_fd; display(prompt);//调用函数显示个性化提示性西 ParaNum=readcmd(&command,parameters,prompt);//读取用户输入的参数,ParaNum=count,2个参数的时候,count=4 if(-1 == ParaNum) continue; ParaNum--;//自减运算ParaNum=count=3 parsing(parameters,ParaNum,&info); int resault; resault=builtin_cmd(command,parameters); if(strcmp(command,"type")==0 && resault) command="which"; if(info.flag & IS_PIPED) //command2 不为空 { if(pipe(pipe_fd)<0) { printf("bashshell error:pipe failed.\n"); exit(0); } } if((ChdPid=fork())==0){ //child process if(info.flag & IS_PIPED) //PIPED { if(!(info.flag & OUT_REDIRECT) && !(info.flag & OUT_REDIRECT_APPEND)) // ONLY PIPED { close(pipe_fd[0]); close(fileno(stdout)); dup2(pipe_fd[1], fileno(stdout)); close(pipe_fd[1]); } else { close(pipe_fd[0]); close(pipe_fd[1]);//send a EOF to command2 if(info.flag & OUT_REDIRECT) //OUT_REDIRECT and PIPED out_fd = open(info.out_file, O_WRONLY|O_CREAT|O_TRUNC, 0666); else //OUT_REDIRECT_APPEND and PIPED out_fd = open(info.out_file, O_WRONLY|O_APPEND|O_TRUNC, 0666); close(fileno(stdout)); dup2(out_fd, fileno(stdout)); close(out_fd); } } else//NOT PIPED { if(info.flag & OUT_REDIRECT) // OUT_REDIRECT WITHOUT PIPE { out_fd = open(info.out_file, O_WRONLY|O_CREAT|O_TRUNC, 0666); close(fileno(stdout)); dup2(out_fd, fileno(stdout)); close(out_fd); } if(info.flag & OUT_REDIRECT_APPEND) // OUT_REDIRECT_APPEND WITHOUT PIPE { out_fd = open(info.out_file, O_WRONLY|O_CREAT|O_APPEND, 0666); close(fileno(stdout)); dup2(out_fd, fileno(stdout)); close(out_fd); } } if(info.flag & IN_REDIRECT)//INREDIRECT { in_fd = open(info.in_file, O_CREAT |O_RDONLY, 0666); close(fileno(stdin)); dup2(in_fd, fileno(stdin)); close(in_fd); } execvp(command,parameters); } else{ //parent process if(info.flag & IS_PIPED) { if((ChdPid2=fork()) == 0) //command2 { //children process close(pipe_fd[1]); close(fileno(stdin)); dup2(pipe_fd[0], fileno(stdin)); close(pipe_fd[0]); execvp(info.command2,info.parameters2); } else { //parent process close(pipe_fd[0]); close(pipe_fd[1]); waitpid(ChdPid2,&status,0); //wait command2 } } if(info.flag & BACKGROUND)//backgroud { printf("Child pid:%u\n",ChdPid); int i; for(i=0;i<MAXPIDTABLE;i++) if(BPTable[i]==0) BPTable[i] = ChdPid; //register a background process if(i==MAXPIDTABLE) perror("Too much background processes\nThere will be zombine process"); } else { waitpid(ChdPid,&status,0);//wait command1 } }//end else }//end while free(parameters); free(buffer); }
- 运维脚本
文件备份相关的
rotate_log.sh [-nz] [-m|--mode copytruncate|move] [-s|--size maxsize] filename
#!/bin/bash #全局变量,用来避免执行操作的时候覆盖已有的文件 i=1 #各执行函数 #—— 1—— 压缩参数-z function execp_z(){ gzip "$filepath" } #——2 ——询问是否备份参数-n function execp_n(){ echo "are you sure to backup""$filepath""?" } #——3 ——有大小限制的备份 -s(minfilesize) function execp_s(){ real=`ls -l $filepath | awk '{ print $5 }'` #start 将系统文件的大小和输入的阈值进行单位的统一,都统一为K max=$1 max=${max/M/000} max=${max/G/000000} max=${max/K/} real=${real/K/} #end #当系统文件的大小real大于输入的文件大小max的时候 if [ "$max" -le "$real" ] ;then { #文件的重名检查 while [ -f "$filepath"".""$i" ] ; do i=i+1; done; #备份操作 mv "$filepath" "$filepath"".""$i" } fi } #—— 4 ——分模式备份-mmove和-mcopytruncate function execp_m(){ if [ "$1" = 'move' ] ;then { while [ -f "$filepath"".""$i" ] ; do i=i+1; done; mv "$filepath" "$filepath"".""$i" } elif [ "$1" = 'copytruncate' ] ;then { while [ -f "$filepath"".""$i" ] ; do i=$((i+1)) done; cp "$filepath" "$filepath"".""$i" truncate --size 0 "$filepath" } fi } #主解析函数,所有命令在这里解析 function execp(){ #num中存放从主函数传来的参数个数 num=$# #第一参数为n if [ "$1" = 'n' ] ;then { #参数为-nz的情况 if [ "$num" -eq 2 -a "$2"='z' ] ;then execp_n execp_z #参数为-n的情况 elif [ "$num" -eq 1 ] ;then execp_n else echo "$error" fi } #第一个参数为z elif [ "$1" = 'z' ] ;then { #参数为-zn的情况 if [ "$num" -eq 2 -a "$2"='n' ] ;then execp_z execp_n #参数为-z的情况 elif [ "$num" -eq 1 ] ;then execp_z else echo "$error" fi } #第一个参数为m elif [ "$1" = 'm' ] ;then { #不带值的情况,默认为move模式 if [ "$num" -eq 1 ] ;then execp_m 'move' #带值的情况 elif [ "$num" -eq 2 ] ;then { #符合值的取值 if [ "$2"='move' -o "$2"='copytruncate' ] ;then execp_m $2 else echo "$error" fi } else echo "$error" fi } ##第一个参数为s elif [ "$1" = 's' ] ;then { #带值的情况 if [ "$num" -eq 2 ] ;then execp_s $2 else echo "$error" fi } fi } #主函数 #读取文件名 filename=${!#} #读取当前路径 pwd=$PWD #拼接出文件绝对路径 filepath="$pwd"/"$filename" #循环的分析logrotate.h后面的参数列表 for p in $@; do if [ "$p" != "$filename" ] ;then { #p中的字母数等于两个的情况,意味着为-n,-z,-m等可以不带值的参数 if [ ${#p} -eq 2 ] ;then { #para中存放着参数的字母,例如m,n,z,s,等等 para=${p:1:1} #进入解析执行函数execp execp $para } #p中的字母数大于两个的情况,意味这为-s,-m等需要带值的参数,或者多个无值参数 elif [ ${#p} -gt 2 ] ;then { #para中存放参数的字母 para=${p:1:1} #mode中存放参数字母后面所带的值,例如-s500K,这里mode=500K mode=${p:2} #进入解析执行函数 execp $para $mode } else echo "error" fi } fi done;