Python 实现一个mini shell

mini shell 的想法是通过python实现一个类似与linux的shell。目前只支持4条命令 ls,cat,cd,history。(如果exit也算一条命令的话,那就是五条)。
功能也类似与linux的shell,比如说运行这个python的程序之后,输入ls,它会返回当前目录的文件和文件夹。

通过这个小demo:

  1. 可以熟悉一个python下面os库的一些函数,比如说如何获取当前工作目录,主机名,用户名等等。
  2. 熟悉signal信号机制,比如我们在linux下面输入ctrl+c 是挂起信号,但是你在mini shell里面要屏蔽这个信号,因为并不希望ctrl+c就退出当前的minishell。
  3. 了解一下shell,在学习linux的时候,其实对shell刚接触的时候,会有很大的恐惧感。其实我们在shell下输入的命令,比如cat,ls 他们的本质都是可执行文件,位于系统的bin目录下面。
    输入ls -l,就好像我们现在有一个可执行文件叫 a.out,
//-l 相当于是参数,通过mian的argv获得
./a.out   -l  

ls和自己写得a.out 的区别在于,a.out必须在当前目录下才可以执行,但是ls可以在任何目录。你可以更改环境变量,把a.out的当前目录,加入到环境变量里面,这样就可以了。(这也就是我们安装java,python,mysql 等为什么要配置环境变量的原因了)

前面可以参考:
Python 在linux下获得当前工作目录,主机名,用户名,操作系统平台等信息http://www.jianshu.com/p/5c294b5bc7b9

运行结果:

《Python 实现一个mini shell》 image.png

这是一个未完工的版本:
history的命令,exit命令还没有实现,也没有写成一个循环。有空来更新。实验是参考实验楼的一个python教程。

解释器的版本是python2.7,换成3也没有问题,稍微改一下print函数就可以。

#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('~') 获取当前操作系统平台的当前用户根目录
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):
    # 其实就是按空格符将命令与参数分开
    # 比如,'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

#構建一個字典 字典裏面的value,指的是函數,比如cd是cd函數
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 這裏應該寫成一個循環 

#輸出
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)
    原文作者:zhaozhengcoder
    原文地址: https://www.jianshu.com/p/30bac36a7651
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞