How to create your own Shell with Python (Part 2)

巴扎黑
Release: 2017-03-18 11:54:37
Original
1124 people have browsed it

In the previous article, we have created a shell main loop, split the command input, and executed the command throughforkandexec. In this part, we will address the remaining issues. First of all, thecd test_dir2command cannot modify our current directory. Second, we still can't exit gracefully from the shell.

Step 4: Built-in command

"cd test_dir2cannot modify our current directory" This sentence is correct, but it is also wrong in a sense. It's correct in the sense that we are still in the same directory after executing the command. However, the directory has actually been modified, but it has been modified in the child process.

Remember that we forked a child process and then executed the command. The process of executing the command did not occur on the parent process. The result is that we only change the current directory of the child process, not the directory of the parent process.

Then the child process exits, and the parent process continues to run in the intact directory.

Therefore, such commands related to the shell itself must be built-in commands. It must be executed in the shell process and not in forking.

cd

Let’s start with thecdcommand.

We first create abuiltinsdirectory. Every built-in command will be placed in this directory.

yosh_project |-- yosh |-- builtins | |-- __init__.py | |-- cd.py |-- __init__.py |-- shell.py
Copy after login

Incd.py, we implement our owncdcommand by using the system callos.chdir.

import os from yosh.constants import * def cd(args): os.chdir(args[0]) return SHELL_STATUS_RUN
Copy after login

Note that we will return the running status of the shell from the built-in function. So, to be able to continue using constants in the project, we moved them toyosh/constants.py.

yosh_project |-- yosh |-- builtins | |-- __init__.py | |-- cd.py |-- __init__.py |-- constants.py |-- shell.py
Copy after login

Inconstants.py, we put all the state constants here.

SHELL_STATUS_STOP = 0 SHELL_STATUS_RUN = 1
Copy after login

Now, our built-incdis ready. Let's modifyshell.pyto handle these built-in functions.

... ### 导入常量 from yosh.constants import * ### 使用哈希映射来存储内建的函数名及其引用 built_in_cmds = {} def tokenize(string): return shlex.split(string) def execute(cmd_tokens): ### 从元组中分拆命令名称与参数 cmd_name = cmd_tokens[0] cmd_args = cmd_tokens[1:] ### 如果该命令是一个内建命令,使用参数调用该函数 if cmd_name in built_in_cmds: return built_in_cmds[cmd_name](cmd_args) ...
Copy after login

We use a python dictionary variablebuilt_in_cmdsas a hash map hash map to store our built-in functions. We extract the name and parameters of the command in theexecutefunction. If the command is in our hash map, the corresponding built-in function is called.

(Tip:built_in_cmds[cmd_name]returns a function reference that can be called directly with arguments.)

We are almost ready to use the built-incdfunction. The final step is to add thecdfunction to thebuilt_in_cmdsmapping.

... ### 导入所有内建函数引用 from yosh.builtins import * ... ### 注册内建函数到内建命令的哈希映射中 def register_command(name, func): built_in_cmds[name] = func ### 在此注册所有的内建命令 def init(): register_command("cd", cd) def main(): ###在开始主循环之前初始化 shell init() shell_loop()
Copy after login

We define theregister_commandfunction to add a built-in function to our built-in command hash map. Next, we define theinitfunction and register the built-incdfunction here.

Pay attention to this lineregister_command("cd", cd). The first parameter is the name of the command. The second parameter is a function reference. In order to allow the second parametercdto refer to thecdfunction reference inyosh/builtins/cd.py, we must put the following line of code inyosh/builtins/__init__.pyfile.

from yosh.builtins.cd import *
Copy after login

So, inyosh/shell.py, when we import*fromyosh.builtins, we can get theyosh.builtinsImportedcdfunction reference.

We have the code ready. Let us try to run our shell as a module in the same directory asyosh,python -m yosh.shell.

Now, thecdcommand can correctly modify our shell directory, and non-built-in commands can still work. very good!

exit

The final piece is finally here: exit gracefully.

We need a function that can modify the shell status toSHELL_STATUS_STOP. In this way, the shell loop can end naturally and the shell will reach the end and exit.

Same ascd, if we fork and execute theexitfunction in the child process, it will have no effect on the parent process. Therefore, theexitfunction needs to be a shell built-in function.

Let’s start here: Create a new file calledexit.pyin thebuiltinsdirectory.

yosh_project |-- yosh |-- builtins | |-- __init__.py | |-- cd.py | |-- exit.py |-- __init__.py |-- constants.py |-- shell.py
Copy after login

exit.pydefines aexitfunction, which only returns a status that can exit the main loop.

from yosh.constants import * def exit(args): return SHELL_STATUS_STOP
Copy after login

Then, we import theexitfunction reference located in theyosh/builtins/__init__.pyfile.

from yosh.builtins.cd import * from yosh.builtins.exit import *
Copy after login

Finally, we register theexitcommand in theinit()function inshell.py.

... ### 在此注册所有的内建命令 def init(): register_command("cd", cd) register_command("exit", exit) ...
Copy after login

That’s it!

Try to executepython -m yosh.shell. Now you can typeexitto exit the program gracefully.

Final Thoughts

I hope you enjoy creatingyosh(yourown ## as much as I did) #shell) process. But my version ofyoshis still in its early stages. I didn't deal with some corner cases that would crash the shell. There are a lot of built-in commands that I didn't cover. To improve performance, some non-builtin commands can also be implemented as built-in commands (to avoid new process creation time). At the same time, a large number of features have not yet been implemented.

I have provided the source code at https://github.com/supasate/yosh. Please feel free to fork and try it out.

Now it's time to create a shell that is truly your own.

Happy Coding!

The above is the detailed content of How to create your own Shell with Python (Part 2). For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!