如何寫一個簡單的shell


如何寫一個簡單的shell

看完《UNIX環境高級編程》后我就一直想寫一個簡單的shell來作為練習,因為有事斷斷續續的寫了好幾個月,如今寫了差不多來總結一下。

源代碼放在了Github: https://github.com/yibo141/Oh-Shell

簡單的分析

我們的shell不像bash那樣復雜全面,只是實現其中的一小部分功能:命令歷史,命令補全,支持IO重定向和管道。一共分成幾個部分:主

函數文件,輸出出錯信息,解析命令等。

我們打開bash對照着做,首先bash有命令提示符,我們要做的和bash的命令提示符一樣。然后我們讀取用戶輸入的命令並使用readline庫

將命令添加到歷史命令列表。然后我們將命令傳遞給解析命令函數,解析命令並執行。

輸出命令提示符

打開bash后我們看到初始的命令提示符如下圖所示:

以root登錄后用cd命令切換到別的工作目錄后如下圖所示:

我們發現bash的命令提示符格式為[用戶名]@[主機名]:[當前工作目錄][$或#]。可以看出用戶的home目錄以~表示,而結尾部分的$或#是

指如果當前用戶是普通用戶,則命令提示符是$;如果當前用戶是root用戶,則命令提示符為#。

那么該如何實現呢?我們用getpwuid函數獲取用戶的信息,包括用戶名和用戶ID;用gethostname函數獲取主機名;用getcwd函數獲

取當前用戶的當前工作目錄。有了用戶ID我們就能判斷當前用戶是不是root,因為root用戶的用戶ID為0。有了當前工作目錄我們就能判斷

工作目錄是不是在用戶的home目錄下,如果在home目錄下我們就將home目錄的部分替換成~。這樣打印提示符的任務就完成了,此部分代碼

的實現在main.c文件中的getPrompt函數中。

命令歷史和命令補全

Linux默認保存最后輸入的500個命令歷史。我們可以用GNU的readline庫實現命令歷史和命令補全。安裝就按其中的說明的步驟進

行就行。readline的庫有很多功能,但我們只需要其中的readline函數和add_history函數就行了。readline函數以一個字符串為參

數作為提示符,返回用戶輸入的一行命令;add_history函數以一個字符串作為參數,並將此字符串添加到歷史命令列表里。

打印出錯消息

在err.h頭文件中聲明了3個錯誤處理函數:err_ret函數打印出錯消息並返回,err_quiterr_sys函數打印出錯消息並退出程序。其

后兩個函數在發生致命錯誤時調用,而err_ret函數在發生非致命錯誤時調用。其實現在err.c文件中。其實現是參照《UNIX環境高級編程》

中的出錯處理函數。

實現IO重定向和管道

處理諸如cat < in.data | grep str | sort > out.data這樣的命令需要實現IO重定向和管道。默認情況下在shell中運行的程序其標准輸

入(描述符為0)和標准輸出(描述符為1)都關聯到終端,IO重定向是指將程序的標准輸入和標准輸出重定向到文件或其他設備。shell從描

述符0讀,從描述符1寫。如果我們想將標准輸入重定向就得關閉描述符0,再將其他文件或設備關聯到描述符0。對於標准輸出也一樣。

管道是將進程的標准輸入和/或標准輸出通過一個數據通道與另一個進程關聯。以本節開頭的那個例子來說,grep的標准輸入來自cat

序的輸出,標准輸出則作為sort程序的標准輸入。我們可以用pipe函數創建一個管道,其參數是一個int型數組(假設為fd[2]),數組有

兩個元素。經由數組返回兩個文件描述符,fd[0]為讀而打開,fd[1]為寫而打開。fd[1]的輸出是fd[0]的輸入。如果想重定向標准輸入,則將

標准輸入與fd[0]相關聯,如果想重定向標准輸出,則將標准輸出與fd[1]相關聯。

命令解析

我認為命令解析是這個程序中最難的部分了,可能是我沒學過編譯原理的原因。所以我死扣了好長時間還是不會怎樣解析shll命令(現在也沒

搞通)。我偶然發現在xv6課程主頁上有一個homework是關於這個的,它給出了解析命令的框架,將關鍵的部分空出來

讓學生補全,所以我就照搬出來用了。所以實現的功能也有限,還有命令列表和后台命令不會解析。等以后我看了編譯原理后再把這個坑填了。

總結

這個shell雖然簡單,但也讓我學到了很多知識,查了很多資料。看完《UNIX環境高級編程》后收獲了很多,最高興的莫過於將學到的知識用在

實際的程序中。就寫到這里吧。

Reference:

《UNIX環境高級編程 第三版》

xv6: https://pdos.csail.mit.edu/6.828/2014/xv6.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM