本期主要分享的是一个通过IO函数接口实现的一个minishell(也就是常用的Linux操作命令),如果小伙伴们能够把这个项目理解深刻,那么对于IO函数接口操作的使用以后应该是没有什么问题滴!希望各位小伙伴们深刻理解这个小项目,以此达到巩固我们学习IO函数接口的目的,在嵌入式开发的道路上又进一步!
以下博主赠上源码:
这里呢需要给大家说明一下,下文代码就是本项目完整代码,模块化非常清晰,由于代码量相对较少,所以唯一不足就是没能进行多文件划分,因此大家使用时只需要复制代码运行即可!但是不能只是复制粘贴哦!!!
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <grp.h>
#include <pwd.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
//ls-l功能
int myLs_L(const char *filename)
{
struct stat buf;
int ret = -1;
struct passwd *pwd;
struct group *grp;
char *pmon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Otc", "Nov", "Dec"};
ret = lstat(filename, &buf); //获取文件属性
if (-1 == ret)
{
perror("fail to stat");
return -1;
}
if (S_ISREG(buf.st_mode)) //判断文件类型
{
putchar('-');
}
else if (S_ISDIR(buf.st_mode))
{
putchar('d');
}
else if (S_ISCHR(buf.st_mode))
{
putchar('c');
}
else if (S_ISBLK(buf.st_mode))
{
putchar('b');
}
else if (S_ISLNK(buf.st_mode))
{
putchar('l');
}
else if (S_ISSOCK(buf.st_mode))
{
putchar('s');
}
else if (S_ISFIFO(buf.st_mode))
{
putchar('p');
}
buf.st_mode & S_IRUSR ? putchar('r') : putchar('-'); //判断本用户的权限
buf.st_mode & S_IWUSR ? putchar('w') : putchar('-');
buf.st_mode & S_IXUSR ? putchar('x') : putchar('-');
buf.st_mode & S_IRGRP ? putchar('r') : putchar('-'); //判断本组用户的权限
buf.st_mode & S_IWGRP ? putchar('w') : putchar('-');
buf.st_mode & S_IXGRP ? putchar('x') : putchar('-');
buf.st_mode & S_IROTH ? putchar('r') : putchar('-'); //判断其他用户的权限
buf.st_mode & S_IWOTH ? putchar('w') : putchar('-');
buf.st_mode & S_IXOTH ? putchar('x') : putchar('-');
printf(" %ld", buf.st_nlink); //打印硬链接个数
pwd = getpwuid(buf.st_uid); //获得用户信息
printf(" %s", pwd->pw_name);
grp = getgrgid(buf.st_gid); //获得组信息
printf(" %s", grp->gr_name);
struct tm *ptm = NULL;
ptm = localtime(&buf.st_ctime); //获得时间信息
printf(" %s", pmon[ptm->tm_mon]);
printf(" %02d", ptm->tm_mday);
printf(" %02d:%02d", ptm->tm_hour, ptm->tm_min);
printf(" %s", filename);
putchar('\n');
return 0;
}
//从终端接收命令并解析
int getCmdFromTerminal(char *cmd, char (*file)[128])
{
int i = 1;
int j = 0;
char *ptm = NULL;
fgets(cmd, 128, stdin);
cmd[strlen(cmd) - 1] = 0;
// printf("==%s==\n", cmd);
strcpy(file[0],strtok(cmd, " "));
while (1)
{
ptm = strtok(NULL, " ");
// printf("=%s=\n", cmd);
if (NULL == ptm)
{
break;
}
strcpy(file[i], ptm);
++i;
}
return 0;
}
//ls功能
int myLs(const char *filename)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
dp = opendir(filename);
if (NULL == dp)
{
perror("fail to opendir");
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if (pp->d_name[0] == '.')
{
continue;
}
printf("%s ", pp->d_name);
}
putchar('\n');
closedir(dp);
return 0;
}
//创建文件
int myTouch(const char *filename)
{
int fd = 0;
fd = open(filename, O_CREAT, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
close(fd);
return 0;
}
//文件拷贝
int myCp(const char *dst, const char *src)
{
FILE *fp1 = NULL;
FILE *fp2 = NULL;
char tmpbuff[1024] = {0};
size_t ret = -1;
fp1 = fopen(src, "r");
if (NULL == fp1)
{
perror("fail to fopen");
return -1;
}
fp2 = fopen(dst, "w");
if (NULL == fp2)
{
perror("fail to fopen");
return -1;
}
while (1)
{
ret = fread(tmpbuff, 1, sizeof(tmpbuff), fp1);
if (0 == ret)
{
break;
}
fwrite(tmpbuff, 1, ret, fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
//将文件内容输出在终端
int myCat(const char *filename)
{
FILE *fp = NULL;
char tmpbuff[4096] = {0};
int ret = -1;
fp = fopen(filename, "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)
{
ret = fread(tmpbuff, 1, sizeof(tmpbuff), fp);
if (0 == ret)
{
break;
}
fwrite(tmpbuff, 1, ret, stdout); //stdout是行缓存,遇到\n就会刷新流
}
fclose(fp);
return 0;
}
//执行命令
int execMiniShell(char (*cmd)[128])
{
char pwd[256] = {0};
int ret;
if (!strcmp(cmd[0], "ls") && !strcmp(cmd[1], "-l")) //实现ls-l命令
{
myLs_L(cmd[2]);
}
else if (!strcmp(cmd[0], "ls"))
{
if(cmd[1][0] == 0) //实现ls命令
{
strcpy(cmd[1], ".");
myLs(cmd[1]);
}
else
{
myLs(cmd[1]); //遍历任意一个目录下的文件
}
}
else if (!strcmp(cmd[0], "touch")) //创建文件
{
myTouch(cmd[1]);
}
else if (!strcmp(cmd[0], "rm")) //删除文件
{
remove(cmd[1]);
}
else if (!strcmp(cmd[0], "mkdir")) //创建文件夹
{
mkdir(cmd[1], 0664);
}
else if (!strcmp(cmd[0], "rmdir")) //删除文件夹
{
rmdir(cmd[0]);
}
else if (!strcmp(cmd[0], "cd")) //改变当前工作路径
{
chdir(cmd[1]);
}
else if (!strcmp(cmd[0], "cp")) //实现文件拷贝
{
myCp(cmd[2], cmd[1]);
}
else if (!strcmp(cmd[0], "pwd")) //打印当前工作目录
{
getcwd(pwd, sizeof(pwd));
printf("%s\n", pwd);
}
else if (!strcmp(cmd[0], "mv")) //修改某个文件名
{
rename(cmd[1], cmd[2]);
}
else if (!strcmp(cmd[0], "cat")) //在终端查看文件内容
{
myCat(cmd[1]);
}
else if (!strcmp(cmd[0], "chmod")) //修改文件权限
{
int mode = atoi(cmd[2]);
if (mode > 0)
{
chmod(cmd[1], mode);
}
}
else if (!strcmp(cmd[0], "ln") && cmd[1][0] != '-') //创建硬链接
{
ret = link(cmd[1], cmd[2]);
if (-1 == ret)
{
perror("fail to link");
}
}
else if (!strcmp(cmd[0], "ln") && !strcmp(cmd[1], "-s")) //创建软连接
{
ret = symlink(cmd[3], cmd[2]);
if (-1 == ret)
{
perror("fail to symlink");
}
}
return 0;
}
int main(int argc, const char *argv[])
{
char cmdbuf[128] = {0};
char cmd[10][128] = {0};
char pwd[256] = {0};
while (1)
{
getcwd(pwd, sizeof(pwd)); //获取当前工作路径
printf("[linux@ckp:%s$]", pwd); //打印minishell的用户戳
getCmdFromTerminal(cmdbuf, cmd); //获取命令并进行解析
execMiniShell(cmd); //执行命令
}
return 0;
}
各位小伙伴们,本期的分享到这里就结束啦!希望通过这个项目大家能够快速掌握Linux的shell命令以及Linux下的IO操作的函数接口,每经过一个小项目,我们距离嵌入式开发工程师的目标就更进一步,加油!最后,欢迎各位小伙伴评论留言私信哦!