要了解有关外壳的更多信息,请单击 在这里 .
null
我们都在Ubuntu、Fedora等Linux发行版中使用内置的终端窗口,但它们实际上是如何工作的呢?在本文中,我们将处理一些 引擎盖下 在外壳中实际工作的特性和算法。所有Linux操作系统都有一个终端窗口来写入命令。但它们进入后如何正确执行? 另外,如何处理保留命令历史记录和显示帮助等额外功能?所有这些都可以通过创建自己的shell来理解。
基础知识
输入命令后,将执行以下操作:
- 输入命令,如果长度不为空,则将其保留在历史记录中。
- 解析:解析是将命令分解为单个单词和字符串
- 检查管道等特殊字符
- 检查是否需要内置命令。
- 如果 管 正在处理管道。
- 通过执行系统命令和库 分叉 孩子和呼唤 执行 .
- 打印当前目录名并请求下一次输入。
为了保存命令的历史记录,使用箭头键恢复历史记录,以及使用tab键处理autocomplete,我们将使用GNU提供的readline库。
实施
要安装readline库,请打开terminal窗口并写入
sudo apt-get install libreadline-dev
它会询问你的密码。输入它。在下一步中按y键。
- 打印目录可以使用 getcwd .
- 获取用户名可以通过以下方式完成: getenv(“用户”)
- 解析可以通过使用 STREP(“”) .它将根据空格分隔单词。总是跳过长度为零的单词,以避免存储额外的空格。
- 解析后,检查内置命令列表,如果存在,则执行它。如果不是,则将其作为系统命令执行。要检查内置命令,请将命令存储在字符指针数组中,并将所有命令与 strcmp() . 注意:“cd”不能使用execvp在本机工作,因此它是一个内置命令,使用 chdir() .
- 为了执行系统命令,将创建一个新的子级,然后使用execvp执行命令,并等待它完成。
- 检测管道也可以通过使用 STREP(“|”) 。要处理管道,请首先将命令的第一部分与第二部分分开。然后在解析每个部分后,使用execvp在两个单独的新子级中调用这两个部分。管道是指将第一个命令的输出作为第二个命令的输入传递。
- 声明一个大小为2的整数数组,用于存储文件描述符。文件描述符0用于读取,1用于写入。
- 使用pipe()函数打开管道。
- 创建两个孩子。
- 在儿童1->
Here the output has to be taken into the pipe. Copy file descriptor 1 to stdout. Close file descriptor 0. Execute the first command using execvp()
- 儿童2->
Here the input has to be taken from the pipe. Copy file descriptor 0 to stdin. Close file descriptor 1. Execute the second command using execvp()
- 等这两个孩子在家长会议上结束。
// C Program to design a shell in Linux #include<stdio.h> #include<string.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/wait.h> #include<readline/readline.h> #include<readline/history.h> #define MAXCOM 1000 // max number of letters to be supported #define MAXLIST 100 // max number of commands to be supported // Clearing the shell using escape sequences #define clear() printf(" 33[H 33[J") // Greeting shell during startup void init_shell() { clear(); printf ( "******************" "************************" ); printf ( " ****MY SHELL****" ); printf ( " -USE AT YOUR OWN RISK-" ); printf ( "*******************" "***********************" ); char * username = getenv ( "USER" ); printf ( "USER is: @%s" , username); printf ( "" ); sleep(1); clear(); } // Function to take input int takeInput( char * str) { char * buf; buf = readline( ">>> " ); if ( strlen (buf) != 0) { add_history(buf); strcpy (str, buf); return 0; } else { return 1; } } // Function to print Current Directory. void printDir() { char cwd[1024]; getcwd(cwd, sizeof (cwd)); printf ( "Dir: %s" , cwd); } // Function where the system command is executed void execArgs( char ** parsed) { // Forking a child pid_t pid = fork(); if (pid == -1) { printf ( "Failed forking child.." ); return ; } else if (pid == 0) { if (execvp(parsed[0], parsed) < 0) { printf ( "Could not execute command.." ); } exit (0); } else { // waiting for child to terminate wait(NULL); return ; } } // Function where the piped system commands is executed void execArgsPiped( char ** parsed, char ** parsedpipe) { // 0 is read end, 1 is write end int pipefd[2]; pid_t p1, p2; if (pipe(pipefd) < 0) { printf ( "Pipe could not be initialized" ); return ; } p1 = fork(); if (p1 < 0) { printf ( "Could not fork" ); return ; } if (p1 == 0) { // Child 1 executing.. // It only needs to write at the write end close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); close(pipefd[1]); if (execvp(parsed[0], parsed) < 0) { printf ( "Could not execute command 1.." ); exit (0); } } else { // Parent executing p2 = fork(); if (p2 < 0) { printf ( "Could not fork" ); return ; } // Child 2 executing.. // It only needs to read at the read end if (p2 == 0) { close(pipefd[1]); dup2(pipefd[0], STDIN_FILENO); close(pipefd[0]); if (execvp(parsedpipe[0], parsedpipe) < 0) { printf ( "Could not execute command 2.." ); exit (0); } } else { // parent executing, waiting for two children wait(NULL); wait(NULL); } } } // Help command builtin void openHelp() { puts ( "***WELCOME TO MY SHELL HELP***" "Copyright @ Suprotik Dey" "-Use the shell at your own risk..." "List of Commands supported:" ">cd" ">ls" ">exit" ">all other general commands available in UNIX shell" ">pipe handling" ">improper space handling" ); return ; } // Function to execute builtin commands int ownCmdHandler( char ** parsed) { int NoOfOwnCmds = 4, i, switchOwnArg = 0; char * ListOfOwnCmds[NoOfOwnCmds]; char * username; ListOfOwnCmds[0] = "exit" ; ListOfOwnCmds[1] = "cd" ; ListOfOwnCmds[2] = "help" ; ListOfOwnCmds[3] = "hello" ; for (i = 0; i < NoOfOwnCmds; i++) { if ( strcmp (parsed[0], ListOfOwnCmds[i]) == 0) { switchOwnArg = i + 1; break ; } } switch (switchOwnArg) { case 1: printf ( "Goodbye" ); exit (0); case 2: chdir(parsed[1]); return 1; case 3: openHelp(); return 1; case 4: username = getenv ( "USER" ); printf ( "Hello %s.Mind that this is " "not a place to play around." "Use help to know more.." , username); return 1; default : break ; } return 0; } // function for finding pipe int parsePipe( char * str, char ** strpiped) { int i; for (i = 0; i < 2; i++) { strpiped[i] = strsep(&str, "|" ); if (strpiped[i] == NULL) break ; } if (strpiped[1] == NULL) return 0; // returns zero if no pipe is found. else { return 1; } } // function for parsing command words void parseSpace( char * str, char ** parsed) { int i; for (i = 0; i < MAXLIST; i++) { parsed[i] = strsep(&str, " " ); if (parsed[i] == NULL) break ; if ( strlen (parsed[i]) == 0) i--; } } int processString( char * str, char ** parsed, char ** parsedpipe) { char * strpiped[2]; int piped = 0; piped = parsePipe(str, strpiped); if (piped) { parseSpace(strpiped[0], parsed); parseSpace(strpiped[1], parsedpipe); } else { parseSpace(str, parsed); } if (ownCmdHandler(parsed)) return 0; else return 1 + piped; } int main() { char inputString[MAXCOM], *parsedArgs[MAXLIST]; char * parsedArgsPiped[MAXLIST]; int execFlag = 0; init_shell(); while (1) { // print shell line printDir(); // take input if (takeInput(inputString)) continue ; // process execFlag = processString(inputString, parsedArgs, parsedArgsPiped); // execflag returns zero if there is no command // or it is a builtin command, // 1 if it is a simple command // 2 if it is including a pipe. // execute if (execFlag == 1) execArgs(parsedArgs); if (execFlag == 2) execArgsPiped(parsedArgs, parsedArgsPiped); } return 0; } |
要运行代码——
gcc shell.c -lreadline ./a.out
本文由 超级机器人 .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 贡献极客。组织 或者把你的文章寄到contribute@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。
如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END