mini shell 的想法是通過python實現(xiàn)一個類似與linux的shell茵瀑。目前只支持4條命令 ls腕铸,cat惜犀,cd,history狠裹。(如果exit也算一條命令的話虽界,那就是五條)。
功能也類似與linux的shell涛菠,比如說運行這個python的程序之后莉御,輸入ls,它會返回當(dāng)前目錄的文件和文件夾俗冻。
通過這個小demo:
- 可以熟悉一個python下面os庫的一些函數(shù)礁叔,比如說如何獲取當(dāng)前工作目錄,主機名迄薄,用戶名等等琅关。
- 熟悉signal信號機制,比如我們在linux下面輸入ctrl+c 是掛起信號讥蔽,但是你在mini shell里面要屏蔽這個信號涣易,因為并不希望ctrl+c就退出當(dāng)前的minishell。
- 了解一下shell冶伞,在學(xué)習(xí)linux的時候新症,其實對shell剛接觸的時候,會有很大的恐懼感碰缔。其實我們在shell下輸入的命令账劲,比如cat,ls 他們的本質(zhì)都是可執(zhí)行文件,位于系統(tǒng)的bin目錄下面瀑焦。
輸入ls -l腌且,就好像我們現(xiàn)在有一個可執(zhí)行文件叫 a.out,
//-l 相當(dāng)于是參數(shù),通過mian的argv獲得
./a.out -l
ls和自己寫得a.out 的區(qū)別在于榛瓮,a.out必須在當(dāng)前目錄下才可以執(zhí)行铺董,但是ls可以在任何目錄。你可以更改環(huán)境變量禀晓,把a.out的當(dāng)前目錄精续,加入到環(huán)境變量里面,這樣就可以了粹懒。(這也就是我們安裝java重付,python,mysql 等為什么要配置環(huán)境變量的原因了)
前面可以參考:
Python 在linux下獲得當(dāng)前工作目錄凫乖,主機名确垫,用戶名,操作系統(tǒng)平臺等信息http://www.reibang.com/p/5c294b5bc7b9
運行結(jié)果:
image.png
這是一個未完工的版本:
history的命令帽芽,exit命令還沒有實現(xiàn)删掀,也沒有寫成一個循環(huán)。有空來更新导街。實驗是參考實驗樓的一個python教程披泪。
解釋器的版本是python2.7,換成3也沒有問題搬瑰,稍微改一下print函數(shù)就可以款票。
#coding:utf-8
import os
import sys
import shlex
import getpass
import socket
import signal
import subprocess
import platform
import re
SHELL_STATUS_STOP = 0
SHELL_STATUS_RUN = 1
# 使用 os.path.expanduser('~') 獲取當(dāng)前操作系統(tǒng)平臺的當(dāng)前用戶根目錄
HISTORY_PATH = os.path.expanduser('~') + os.sep + '.shiyanlou_shell_history'
def ls(args):
if len(args)>0:
print os.getcwd()
def cd(args):
if len(args) > 0:
os.chdir(args[0])
else:
os.chdir(os.getenv('HOME'))
print os.getcwd()
return SHELL_STATUS_RUN
def getenv(args):
#print 'test : ',args
if len(args) >0:
print(os.getenv(args))
def exit():
#TO-DO
print ('exit')
def history():
#TO-DO
print ('history')
def cat(arg):
#TO-DO
print ('cat')
def display_cmd_prompt():
user=getpass.getuser()
hostname=socket.gethostname()
cwd=os.getcwd()
base_dir=os.path.basename(cwd)
home_dir=os.path.expanduser('~')
if cwd==home_dir:
base_dir='~'
#sys.stdout.write("[%s@%s %s]$ " % (user, hostname, base_dir))
#改變顏色
sys.stdout.write("[\033[1;33m%s\033[0;0m@%s \033[1;36m%s\033[0;0m] $ " % (user, hostname, base_dir))
sys.stdout.flush()
#這部分使用啦正則表達式來處理
def getsplit(str):
# 其實就是按空格符將命令與參數(shù)分開
# 比如,'ls -l /home/shiyanlou' 劃分之后就是
# ['ls', '-l', '/home/shiyanlou']
#res=re.split(r'\s',str)
res=re.split(r'\s+',str)
return res
def isgetenv(tokens):
token=tokens[0]
#print token
if token.startswith('$'):
getenv(token[1:])
#print os.getenv(token[1:])
return True
else:
return False
#構(gòu)建一個字典 字典裏面的value跌捆,指的是函數(shù)徽职,比如cd是cd函數(shù)
built_in_cmds = {}
built_in_cmds['cd']=cd
built_in_cmds['ls']=ls
built_in_cmds['cat']=cat
built_in_cmds['exit']=exit
built_in_cmds['history']=history
#to-do 這裏應(yīng)該寫成一個循環(huán)
#輸出
display_cmd_prompt()
#等待輸入
cmd=sys.stdin.readline()
#切分
cmd_tokens=getsplit(cmd)
#cmd_tokens=[ls -l]
#cmd_tokens=preprocess(cmd_tokens)
if isgetenv(cmd_tokens)==False:
#print cmd_tokens[0]
#print cmd_tokens[1]
cmd_args=cmd_tokens[1:]
#print cmd_args
if cmd_tokens[0] in built_in_cmds:
#print cmd_args
built_in_cmds[cmd_tokens[0]](cmd_args)