pythonshell是什么_用Python写一个简单的Linux Shell(2)

声明

本人小白,欢迎在评论区提出意见建议。文章未经允许不得转载。

文章首发于我的博客。

一个Linux Shell的基本流程

一个shell启动之后,基本上是按照以下的流程进行工作的。显示提示符(prompt),等待用户输入命令

对命令进行解析(parse)

根据命令执行对应的程序

程序执行完毕,重新从第一步开始,接受新的命令

这篇教程的重点主要是第三步,根据命令执行对应的程序。所以为了简单起见,我们不会实现shell的所有语法。

在Python中创建一个shell

因为我们的目标是实现简化版的shell语法,所以我们可以直接使用Python现有的cmd模组(module)。这是官方文档。

要想使用cmd模组,我们需要先将其导入,然后执行cmd.Cmd().cmdloop()来运行一个简单的互动命令行程序。

import cmd

if __name__ == '__main__':

cmd.Cmd().cmdloop()

但是,我们很快就发现,虽然它确实能够显示提示符,等待并接受用户输入命令,但是无论我们输入什么,它都会给出错误提示。这是因为以上代码建立的是一个空的互动命令行程序。

为了能够自定义这个互动命令行的行为,我们需要以cmd.Cmd作为父类(superclass),通过继承(inheritance),建立我们自己的子类(subclass),然后通过重写(override)特定的方法,来实现我们自己的shell。

import cmd

class PyShell(cmd.Cmd()):

pass # TODO: 重写父类方法

if __name__ == '__main__':

PyShell().cmdloop()

Python中cmd.Cmd类的基本结构

在cmd.Cmd中,通过执行cmdloop方法来进入主循环。在第一次进入主循环时,self.intro中的内容会被显示到屏幕上。随后,self.prompt的内容会被显示到屏幕上,并等待用户输入。

当用户输入完成,cmdloop会对用户的输入进行解析。首先,cmdloop会尝试根据用户的输入,执行对应的do_*方法。举个例子,假设用户输入是exit,那么cmdloop会尝试执行do_exit方法。如果用户的输入有多个词,那么cmdloop会将第一个看成命令,剩下的作为参数。举个例子,假设用户输入的是exit 1,那么cmdloop会尝试执行do_exit这个方法(空格隔开的1会被认为是参数,并作为参数被传入do_exit方法)。如果方法不存在,那么cmdloop会执行default这个方法。default这个方法在父类cmd.Cmd中存粹是显示一条错误信息。这就是为什么一开始我们直接执行cmd.Cmd().cmdloop()的时候无论输入什么命令都会报错。

当do_*或者default方法运行完毕时,cmdloop会进入下一次循环。

因此,我们需要在我们的子类PyShell中对父类的__init__、cmdloop,以及default方法进行重写,并添加一些do_*开头的方法。

实现退出shell的功能

可能细心的读者已经注意到了,这个shell目前为止没有退出功能。只能通过关闭终端(terminal)软件或者按下^C(Control-C)组合键发送键盘中断(Keyboard Interrupt)的方式来结束这个shell。

所以,我们的第一步,是在PyShell中,添加do_exit这个方法。

class PyShell(cmd.Cmd()):

def do_exit(self, arg_str: str) -> None:

exit(0)

do_exit中的参数(parameter)arg_str就是用户的输入中,以第一个空格为分界,右半部分的内容。

举个例子,如果用户输入的是exit,那么arg_str此时就是''。如果用户输入的是exit 1,那么arg_str此时就是字符串'1'。如果用户输入的是exit 1 foo 2 bar,那么arg_str此时就是'1 foo 2 bar'(这部分的空格Python不会自动拆分)。

为了实现可以手动指定以不同退出代码(exit code)退出的功能,我们对do_exit这个方法稍作修改。

import shlex

class PyShell(cmd.Cmd()):

def do_exit(self, arg_str: str) -> None:

"""usage: exit [exitcode]"""

args = shlex.split(arg_str)

if len(args) > 1:

print('exit: too many arguments', file=sys.stderr)

return

if len(args) == 0 or args[0] == '':

exit(0)

try:

exit(int(args[0]))

except ValueError:

print('exit: invalid exit code', file=sys.stderr)

注意,这里我们用shlex.split来处理双引号("")内空格不作为分隔的情况。如果我们直接使用arg_str.split(' '),会出现"hello world"被处理为['"hello', 'world"']的情况。但是如果我们使用的是shlex.split(arg_str),那么"hello world"一定会被正确地处理为['hello world']。

经过修改后的do_exit,只允许最多一个自定的退出代码。如果不提供退出代码,默认为0。有了do_exit方法之后,用户可以使用exit命令来退出我们的shell了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值