Use Python to create your own Shell:part II
[TOC]
Original link and description
- https://hackercollider.com/articles/2016/07/06/create-your-own-shell-in-python-part-2/
- This translation document is originally selected from Linux China , the translation of documents copyright belongs to linux China all
In Part 1, we have created a major shell loop, a segmented command input, and the passing fork
and exec
executing of commands. In this part, we will solve the remaining problems. First, the cd test_dir2
command cannot modify our current directory. Second, we are still unable to gracefully exit from the shell.
Step 4: Built-in commands
"CD Test_dir2 cannot modify our current directory" is correct, but in a sense it is also wrong. After executing the command, we are still in the same directory, in this sense, it is right. However, the directory has actually been modified, except that it was modified in the subprocess.
Remember when we fork a child process and execute the command, the process of executing the command does not occur on the parent process. As a result, we just changed the current directory of the child process, not the parent process's directory.
The child process then exits, and the parent process continues to run under the unchanged directory.
Therefore, this type of command, which is related to the shell itself, must be a built-in command. It must be executed in the shell process without forking (forking).
Cd
Let's start with the cd
command.
We first create a builtins
directory. Each built-in command is placed into this directory.
yosh_project|-- yosh |-- builtins | |-- __init__.py | |-- cd.py |-- __init__.py |-- shell.py
In cd.py
, we implement our own commands by using system calls os.chdir
cd
.
import osfromimport*def cd(args): os.chdir(args[0]) return SHELL_STATUS_RUN
Note that we will return the shell's running state from the built-in function. So, to be able to continue using constants in the project, we move them to yosh/constants.py
.
yosh_project|-- yosh |-- builtins | |-- __init__.py | |-- cd.py |-- __init__.py |-- constants.py |-- shell.py
In constants.py
, we put the state constants here.
=0=1
Now, our built-in cd
is ready. Let's modify shell.py
them to handle these built-in functions.
... # Import constants from yosh.constants import * # Hash map to store built-in function name and reference as key and value Built_in_cmds = {}def tokenize (String): return shlex.split (String) span class= "kw" >def Execute (cmd_tokens): # Extract command name and arguments from Tokens Cmd_name = cmd_tokens[0 ] Cmd_args = cmd_to Kens[1 :] # If the command is a built-in command, invoke it function with Argu ments if cmd_name in built_in_cmds: retu RN Built_in_cmds[cmd_name] (Cmd_args) ...
We use a python dictionary variable built_in_cmds
as a hash map (hash map) to store our built-in functions. We execute
extract the name and parameters of the command in the function. If the command is shot in our hash map, the corresponding built-in function is called.
(Hint: built_in_cmds[cmd_name]
returns a function that can be referenced directly using the argument call.) )
We're almost ready to use the built-in cd
functions. The final step is cd
to add the function to the built_in_cmds
map.
...# Import all built-in function referencesfrom yosh.builtins import *...# Register a built-in function to built-in command hash mapdef register_command(name, func): built_in_cmds[name] = func# Register all built-in commands heredef init(): register_command("cd", cd)def main(): # Init shell before starting the main loop init() shell_loop()
We defined the register_command
function to add a built-in function to our built-in command hash map. Next, we define the init
function and register the built-in cd
function here.
Pay attention to this line register_command("cd", cd)
. The first parameter is the name of the command. The second argument is a function reference. In order to be able to cd
refer to yosh/builtins/cd.py
the function reference in the second argument cd
, we must place the following line in the yosh/builtins/__init__.py
file.
from yosh.builtins.cd import *
So, in yosh/shell.py
, when we import from yosh.builtins
*
, we can get yosh.builtins
a function reference that has been imported cd
.
We've got the code ready. Let's try yosh
to run our shell as a module in a sibling directory python -m yosh.shell
.
Now the cd
command can modify our shell directory correctly, and the non-built command will still work. Very good!
Exit
The last piece finally came: gracefully withdrew.
We need a function that can modify the shell state SHELL_STATUS_STOP
. This way, the shell loop can end naturally and the shell will reach the end and exit.
And cd
, like, if we fork and execute functions in a child process exit
, it does not work for the parent process. Therefore, the exit
function needs to be a shell built-in function.
Let's start with this: builtins
create a new file named under the directory exit.py
.
yosh_project|-- yosh |-- builtins | |-- __init__.py | |-- cd.py | |-- exit.py |-- __init__.py |-- constants.py |-- shell.py
exit.py
Defines a exit
function that simply returns a state that can exit the main loop.
from yosh.constants import *def exit(args): return SHELL_STATUS_STOP
We then import yosh/builtins/__init__.py
the function reference that is located in the file exit
.
from yosh.builtins.cd import *from yosh.builtins.exit import *
Finally, we shell.py
register the command in the init()
function exit
.
...# Register all built-in commands heredef init(): register_command("cd", cd) register_command("exit", exit)...
End
Attempt to execute python -m yosh.shell
. Now you can enter exit
gracefully to exit the program.
The final idea
I want you to enjoy yosh
the process of creating (your own shell) as much as I do. But my yosh
version is still in its early stages. I did not deal with some extreme situations that would cause the shell to crash. There are many built-in commands that I don't have covered. To improve performance, some non-built-in commands can also be implemented as built-in commands (avoid new process creation time). At the same time, a large number of functions have not been implemented (see common features and different features)
I have provided the source code in the Github.com/supasate/yosh. Please feel free to fork and try.
Now it's time to create the Shell you really own.
Happy coding!
via:https://hackercollider.com/articles/2016/07/06/create-your-own-shell-in-python-part-2/
[Translate] Create your own shell:part II using Python