1. 程式人生 > >Linux shell命令解析器(二),命令

Linux shell命令解析器(二),命令

環境:

Ubuntu14-4   核心 4.4.0-135

vim編輯器 7.4 

gcc  4.8.4 

1.1 知識點

  • Shell 的基本概念
  • 檔案相關函式,記憶體相關函式

 1  ls命令語法

ls [選項] [目錄或檔名] 
引數: 
-a:--all的縮寫,顯示所有的檔案,包括隱藏檔案(以.開頭的檔案),參考示例1。(常用) 
-A:--almost-all的縮寫,顯示所有的檔案,包括隱藏檔案,但不包括表示當前目錄.和上級目錄..這兩個檔案,參考示例2。 
-c:和-lt一起使用:顯示列表並且以ctime(檔案狀態最後改變時間)排序。和-l一起使用:顯示ctime並且以檔名排序。其他情況,以ctime排序。參考示例3。 
-d:--directory的縮寫,僅列出目錄本身,而不是列出目錄裡的內容列表,參考示例4。(常用) 
-f:直接列出結果,而不進行排序(ls預設會以檔名排序) 
--color[=WHEN]:是否根據檔案型別顯示顏色,WHEN可以為never、always或者auto 
--full-time:以完整的實際模式顯示(包含年月日時分),類似與ls -l --time-style=full-iso,參考示例5。 
-g:列表顯示結果,和-l類似,但是不顯示檔案所屬者。 
-h:將檔案內容大小以GB、KB等易讀的方式顯示,參考示例6。 
-i:結合-l引數,列出每個檔案的inode,參考示例7。 
-l:列出長資料串,顯示出檔案的屬性與許可權等資料資訊(常用) 
-n:和-l類似,只是顯示的所屬使用者和組不是名稱而是對應的id,參考示例8。 
-r:--reverse,將排序結果以倒序方式顯示,參考示例9。 
-S:以檔案大小排序,參考示例9。 
-t:以修改時間排序 
--help:顯示幫助資訊
 

/*************************************************************************
> File Name: ls.c
> Author:
> Mail:
> Created Time: 2018年10月19日 星期五 07時44分47秒
************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<dirent.h>
#include<grp.h>
#include<pwd.h>
#include<dirent.h>
#define STRLEN 128
#define MAXDIR 10  //支援可最多查詢的目錄
#define START_FLAG 1
#define FLAG_L 1
#define FLAG_A 2
#define FLAG_I 4
#define FLAG_S 8
#define FLAG_K 16
#define FLAG_B 32
#define FLAG_R 64    //R,遞迴
#define FLAG_UMASK 
int get_total(const char *root)
{
	int total = 0;
	DIR *dir = NULL;
	dir = opendir(root);
	if (dir == NULL)
	{
		perror("opendir error");
		exit(1);
	}
	struct dirent *ptr = NULL;
	while ((ptr = readdir(dir)) != NULL)
	{
		if (strcmp(".", ptr->d_name) == 0 || strcmp("..", ptr->d_name) == 0)
		{
			printf("%s\n", ptr->d_name);
			continue;
		}
		if (ptr->d_type == DT_REG)
		{
			total++;
		}
		if (ptr->d_type == DT_DIR)
		{
			printf("%s\n", ptr->d_name);
			char path[128] = { 0 };
			sprintf(path, "%s/%s", root, ptr->d_name);
			total += get_total(path);
		}
	}
	closedir(dir);
	return total;
}
void AlayPath(int argc, char*argv[], char path[][STRLEN], char para[], int *num)
{
	int length = argc;
	int i = 0;
	int count = 0;
	int j = 0;
	DIR *dir = NULL;
	for (i = 0; i < length; i++)
	{
		if (strncmp(argv[i], "-", 1) != 0)
		{
			if ((dir = opendir(argv[i])) != NULL)
			{
				strcpy(path[count++], argv[i]);
				//printf("alaypara %s\n",path[count-1]);
			}
		}
		else
		{
			strcat(para, argv[i]);
		}
	}
	*num = count;
}
void PrintFileName(int mode, char *name)
{
	if (S_ISDIR(mode))    //判斷是否為目錄
	{
		printf("\033[1;34m%s\033[0m   ", name);//檔名顯示為藍色
	}
	else if (S_ISREG(mode)) //判斷是否為普通檔案
	{
		if (mode & S_IXUSR || mode & S_IXGRP || mode & S_IXOTH)//判斷是否為可執行檔案
		{
			printf("\033[1;32m%s\033[0m    ", name);//檔名顯示為綠色
		}
		else
		{
			printf("%s   ", name);
		}
	}
	else
	{
		printf("%s   ", name);
	}

}
//w e y z  無效
//i block
//a 所有檔案
//s 磁碟空間值
//d 當前檔案
//f 所有檔案
//h 單位以k顯示
//k 檔案大小以k值為單位向上取整
//n 檔案所有者及所屬組以整數值表示
//m 逗號分割
//l 詳細資訊
int  AlayPara(char para[], char errpara[], int length, int *flag)
{
	int i = 0;
	int pos = 0;
	*flag = 0;
	int sign = 1;
	for (; i < length; ++i)
	{
		if (para[i] == '-')
		{
			continue;
		}
		else if (para[i] == 'l')
		{
			*flag |= START_FLAG << 0;
		}
		else	if (para[i] == 'a')
		{
			*flag |= START_FLAG << 1;
		}
		else if (para[i] == 'i')
		{
			*flag |= START_FLAG << 2;
		}
		else if (para[i] == 's')
		{
			*flag |= START_FLAG << 3;
		}
		else if (para[i] == 'k')
		{
			*flag |= START_FLAG << 4;
		}
		else if (para[i] == 'b')
		{
			*flag |= START_FLAG << 5;
		}
		else if (para[i] == 'R')
		{
			*flag |= START_FLAG << 6;
		}
		else
		{
			errpara[pos++] = para[i];
			sign = 0;
			break;
		}

	}
	return sign;
}

int main(int argc, char *argv[])
{
	char dirpath[MAXDIR][STRLEN] = { 0 }; //存所傳入的路徑
	char curpath[STRLEN] = { 0 };   //存當前路徑
	char para[STRLEN] = { 0 };      //存引數
	char errpara[STRLEN] = { 0 };   //存非法引數
	struct dirent *ptr = NULL;
	struct dirent *pptr = NULL;
	DIR *dir = NULL;
	int dir_num = 0;                //路徑數目
	int i;
	int ret;
	int t;
	int flag = 0;                  //得到所輸入的路徑的引數
	int length = 0;                //引數長度
	int total = 0;
	struct stat st;
	int inode = 0;
	int blocks = 0;
	int blksize = 0;
	int linkNum = 0;
	char *fileUser = NULL;
	char *fileGrp = NULL;
	int fileSize = 0;
	char *time = NULL;
	char mtime[STRLEN] = { 0 };
	char realtime[STRLEN] = { 0 };
	char buff[1024];
	char perms[12] = { 0 };   // dwrxwrxwrx. 比這11位多一位存‘/0’
	getcwd(curpath, STRLEN - 1);
	if (argc < 2)
	{
		dir = opendir(curpath);
		if (dir != NULL)
		{
			while ((ptr = readdir(dir)) != NULL)
			{
				ret = stat(ptr->d_name, &st);
				if (ret == -1)
				{
					perror("stat");
					exit(1);
				}

				if (strcmp(".", ptr->d_name) == 0 || strcmp("..", ptr->d_name) == 0)
				{
					continue;
				}
				PrintFileName(st.st_mode, ptr->d_name);

			}
		}
	}
	else
	{
		AlayPath(argc, argv, dirpath, para, &dir_num);
		length = strlen(para);
		t = AlayPara(para, errpara, length, &flag);
		//	printf("t==%d flag==%d\n",t,flag);
		if (t == 0)
		{
			printf("ls:invalid option --'%s'\n", errpara);
			printf("Try 'ls -help' for more infomation.\n");
			exit(0);
		}
		for (i = 0; i < dir_num; i++)
		{
			//printf("i===%d dir=%s\n",i,dirpath[i]);
			chdir(curpath);
			getcwd(curpath, STRLEN - 1);
			dir = opendir(dirpath[i]);
			if (dir == NULL)
			{
				perror("opendir fail");
				continue;
			}
			chdir(dirpath[i]);
			while ((pptr = readdir(dir)) != NULL)
			{
				ret = stat(pptr->d_name, &st);
				if (ret == -1)
				{
					perror("stat");
					break;
				}
				if ((strcmp(".", pptr->d_name) == 0 || strcmp("..", pptr->d_name) == 0) && (flag & 2) != 2)
				{
					continue;
				}
				total += st.st_blocks / 2;
			}
			if (flag & 1 == 1 || flag & 8 == 8)
			{
				printf("total %d\n", total);
			}
			total = 0;
			closedir(dir);
			chdir(curpath);
			dir = opendir(dirpath[i]);
			chdir(dirpath[i]);
			while ((ptr = readdir(dir)) != NULL)
			{
				ret = stat(ptr->d_name, &st);
				if (ret == -1)
				{
					perror("stat");
					break;
				}
				blocks = st.st_blocks / 2;
				inode = st.st_ino;
				switch (st.st_mode & S_IFMT)
				{
				case S_IFLNK:perms[0] = 'l';	break;
				case S_IFDIR:perms[0] = 'd';  break;
				case S_IFREG:perms[0] = '-';	break;
				case S_IFBLK:perms[0] = 'b';	break;
				case S_IFCHR:perms[0] = 'c';	break;
				case S_IFSOCK:perms[0] = 's';	break;
				case S_IFIFO:perms[0] = 'p';  break;
				default:break;
				}
				//use
				perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
				perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
				perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
				//group
				perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
				perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
				perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
				//other
				perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
				perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
				perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
				perms[10] = '.';
				//link number
				linkNum = st.st_nlink;
				//fileUser
				fileUser = getpwuid(st.st_uid)->pw_name;
				//fileGrp
				fileGrp = getgrgid(st.st_gid)->gr_name;
				//fileSize
				fileSize = (int)st.st_size;
				//modifyTime
				time = ctime(&st.st_mtime);
				strncpy(mtime, time, strlen(time) - 1);
				memmove(realtime, mtime + 4, 12);
				sprintf(buff, "%s " "%d " "%s " "%s " "%d " "%s ", perms, linkNum, fileUser, fileGrp, fileSize, realtime);
				//	printf("%8s  %4d  %4s  %8s  %8d  %8s %8s",perms,linkNum,fileUser,fileGrp,fileSize,realtime,dirpath);
				printf("%s", buff);
				PrintFileName(st.st_mode, ptr->d_name);
				printf("\n");
				//		closedir(dir);
				//chdir(curpath);
			}
			closedir(dir);
		}
	}
	printf("\n");
	return 0;
}

2 su命令語法

-f , –fast:不必讀啟動檔案(如 csh.cshrc 等),僅用於csh或tcsh兩種Shell。

-l , –login:加了這個引數之後,就好像是重新登陸一樣,大部分環境變數(例如HOME、SHELL和USER等)都是以該使用者(USER)為主,並且工作目錄也會改變。如果沒有指定USER,預設情況是root。

-m, -p ,–preserve-environment:執行su時不改變環境變數。

-c command:變更賬號為USER的使用者,並執行指令(command)後再變回原來使用者。

–help 顯示說明檔案
–version 顯示版本資訊

/*************************************************************************
	> File Name: su.c
	> Author: 
	> Mail: 
	> Created Time: 2018年10月19日 星期五 07時47分05秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<shadow.h>
#include<pwd.h>
#include<sys/stat.h>
#include<sys/types.h>

int main(int argc,char *argv[])
{
    char *user="root";
    if(argv[1]!=NULL)
    {
        user=argv[1];
    }
    printf("Password:");
    fflush(stdout);    //字串刷到終端
    char password[128]={0};
    fgets(password,128,stdin);
    password[strlen(password)-1]=0;

    //根據使用者名稱獲取系統儲存使用者的密碼資訊
    struct spwd *pwd=getspnam(user);
    assert(pwd!=NULL);

    //根據使用者密碼資訊獲取加密演算法ID以及金鑰
    char *p=pwd->sp_pwdp;
    char salt[128]={0};
    int count=0,i=0;
    printf("%s\n",p);
    while(1)
    { 
        salt[i]=*p;
        if(salt[i]=='$')
        {
            count++;
        }
        if(count==3)
        {
            break;
        }
        i++,p++;
    }

    //根據獲取的演算法ID以及金鑰,對輸入的明文加密
    char *s=strcpy(password,salt);
    if(strcmp(s,pwd->sp_pwdp)!=0)
    {
        perror("password is error");
        exit(0);
    }
    pid_t n=fork();
    assert(n!=-1);
    if(n==0)
    {
        struct passwd *pw=getpwnam(user);
        assert(pw!=NULL);
        setenv("HOME",pw->pw_dir,1);//設定環境變數
        setuid(pw->pw_uid);//修改使用者
        execl("a.out",pw->pw_shell,NULL);
        printf("su is fail\n");
        exit(0);
    }
    else

    {
        wait(NULL);
    }

}

3 cp命令語法

-a:此選項通常在複製目錄時使用,它保留連結、檔案屬性,並複製目錄下的所有內容。其作用等於dpR引數組合。

-d:複製時保留連結。這裡所說的連結相當於Windows系統中的快捷方式。

-f:覆蓋已經存在的目標檔案而不給出提示。

-i:與-f選項相反,在覆蓋目標檔案之前給出提示,要求使用者確認是否覆蓋,回答"y"時目標檔案將被覆蓋。

-p:除複製檔案的內容外,還把修改時間和訪問許可權也複製到新檔案中。

-r:若給出的原始檔是一個目錄檔案,此時將複製該目錄下所有的子目錄和檔案。

-l:不復制檔案,只是生成連結檔案。

-help:顯示說明檔案

/*************************************************************************
	> File Name: c.c
	> Author: 
	> Mail: 
	> Created Time: 2018年10月19日 星期五 07時43分27秒
 ************************************************************************/

#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
    if(argc < 2)
    {
        printf("cp: missing file operand\n");
        printf("Try 'cp --help' for more information.\n");
        exit(0);
    }
    if(argc == 2)
    {
        printf("cp: missing destination file operand after '%s'\n",argv[1]);
        printf("Tryy 'cp --help' for more infot=rmation\n");
        exit(0);
    }
    if(argc == 3)
    {
        
    }
    int fd_src=open(argv[1],O_RDONLY);
    if(fd_src==-1)
    {
        perror("open");
        exit(1);
    }
    int fd_dest=open(argv[2],O_WRONLY|O_CREAT|O_EXCL,0644);
    if(fd_dest==-1&&errno==EEXIST)
    {
        printf("recover it?");
        char choose;
        scanf("%c",&choose);
        if(choose=='y'||choose=='Y')
        {
            fd_dest=open(argv[2],O_WRONLY);
        }
        else
        {
            exit(1);
        }
    }
     while(1)
    {
        char buf[1024]={};
        memset(buf,0x00,sizeof(buf));
        int r=read(fd_src,buf,1024);
        if(r==-1)
        {
            perror("read");
            exit(1);
        }
        if(r==0)
        {
             break;     
        }
        write(fd_dest,buf,r);  
    }
    close(fd_src);
    close(fd_dest);                 
    return 0;
}