shell:Linux下,shell爲操作系統的外殼,爲用戶提供了使用操作系統的接口,它是命令語言、命令解釋程序及程序設計語言的統稱。
主要功能:(1)命令解釋器;(2)作爲一種高級程序設計語言可以編寫出代碼簡潔、功能強大的程序。
在這裏主要簡單實現其一大功能:命令解釋器(包括重定向>的實現)
主要過程:當一個用戶登錄後,系統會啓動一個默認的shell程序:
1.可以看到一個字符串和shell的提示符(管理員爲#,普通用戶爲$);
2.在提示符後輸入一串字符串(命令行),它接收用戶輸入的字符串命令,進行分析;
3.創建子進程,由子進程實現命令所規定的功能;
4.子進程結束時,再次發出提示符。
以下用代碼具體實現這4個過程:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
//獲取當前用戶名
void GetLoginname()
{
struct passwd *pwd=getpwuid(getuid());
printf("[%s",pwd->pw_name);
}
//獲取當前主機名
void GetHostname()
{
char name[256]={0};
int ret=gethostname(name,256);
if(ret==0)
printf("@%s",name);
}
//獲取當前路徑
void GetPwd()
{
char pwd[256]={0};
getcwd(pwd,sizeof(pwd)-1);//pwd存儲的爲相對路徑
int len=strlen(pwd);
//用p獲取當前路徑
char* p=pwd+len;
while(*p!='/'&&len--)
--p;
++p;
printf(" %s]#",p);
}
void Myshell()
{
//shell死循環實現4
while(1)
{
//實現1
//printf("[wrq@localhost shell]#");
//打印shell提示符
GetLoginname();
GetHostname();
GetPwd();
fflush(stdout); //刷新緩衝區以便不影響後面讀取
//實現2
//讀字符串到緩衝區中
char buf[1024];
ssize_t ret=read(0,buf,sizeof(buf)-1);//系統調用從標準輸入鍵盤獲取字符串存入緩存buf中
if(ret>0)
buf[ret-1]=0; //將最後一個回車換行‘\n’刷新爲0
//將字符串分解爲逐個命令存入指針數組中
char* argv[32];
int i=0;
argv[i]=buf;
char* start=buf;
while(*start)
{
if((*start)==' ')//若等於空格則一個命令結束
{
*start=0;
++start;
argv[++i]=start;
}
else
{
++start;
}
}
argv[i+1]=NULL; //最後一個初始化爲NULL
//實現3
//創建子進程調用exec()函數進行程序替換
pid_t id=fork();
if(id==0) //child
{
//shell重定向>的實現
int j=0;
int fd;
for(j=0;j<=i;++j)
{
if(strcmp(argv[j],">")==0) //查找數組是否有重定向>符合
{
char* file=argv[j+1]; //有 ,下一個即爲重定向的文件名
argv[j]=NULL; //改變指針數組的有效大小 ,只執行j以前
close(1); //關閉標準輸出顯示器 文件描述符1
fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,0666); //則重新打開重定向的文件 其返回的文件描述符則爲1
//dup2(fd,STDOUT_FILENO); //將fd文件描述符賦值於1
break;
}
}
//在以上重定向符實現中,即使文件描述符表中1的位置(文件描述符1)不在存儲標準輸出stdout文件,存儲的爲file文件地址
//又使指針數組有效大小隻變爲重定向符號>以前,即在下面程序替換中,執行argv中的命令不會顯示在顯示器上,而寫在文件file中
//程序替換
execvp(argv[0],argv);
exit(1);
}
else //father //父進程只等待子進程結束
{
int status=0;
pid_t ret=waitpid(id,&status,0);
}
}
}
int main()
{
Myshell();
return 0;
}